线程数

9种 OOM 常见原因及解决方案

余生长醉 提交于 2020-03-16 21:46:54
当 JVM 内存严重不足时,就会抛出 java.lang.OutOfMemoryError 错误。本文总结了常见的 OOM 原因及其解决方法,如下图所示。如有遗漏或错误,欢迎补充指正。 1、Java heap space 当堆内存(Heap Space)没有足够空间存放新创建的对象时,就会抛出 java.lang.OutOfMemoryError:Javaheap space 错误(根据实际生产经验,可以对程序日志中的 OutOfMemoryError 配置关键字告警,一经发现,立即处理)。 原因分析 Javaheap space 错误产生的常见原因可以分为以下几类: 1、请求创建一个超大对象,通常是一个大数组。 2、超出预期的访问量/数据量,通常是上游系统请求流量飙升,常见于各类促销/秒杀活动,可以结合业务流量指标排查是否有尖状峰值。 3、过度使用终结器(Finalizer),该对象没有立即被 GC。 4、内存泄漏(Memory Leak),大量对象引用没有释放,JVM 无法对其自动回收,常见于使用了 File 等资源没有回收。 解决方案 针对大部分情况,通常只需要通过 -Xmx 参数调高 JVM 堆内存空间即可。如果仍然没有解决,可以参考以下情况做进一步处理: 1、如果是超大对象,可以检查其合理性,比如是否一次性查询了数据库全部结果,而没有做结果数限制。 2、如果是业务峰值压力

线程池与非线程池应用场景及模型对比分析

喜欢而已 提交于 2020-03-16 11:59:44
某厂面试归来,发现自己落伍了!>>> 在网络编程中经常用到线程池和连接池,今天就对其中常用的线程池的基本应用场景和模型做个简单的对比分析。 1、 业务流程对比 a、 非线程池业务流模型: 上图标识了基本的非线程池的线程模型,前端 1 有多少连接则前端客户端 2 与前端服务器端 3 均需建立一对一的线程数进行响应的连接。前端服务器端 3 与后端服务器端 4 也需建立响应数目的线程进行连接处理相关业务。 当一个任务处理完毕后线程退出,在下一个任务到来的时候前端服务器端创建新的线程来处理新的任务。 b 、线程池模型: 上图标识了基本的线程池模型。前端客户端大量的连接通过服务端的任务接收线程将连接任务放入前端服务器端的任务队列中,前端服务器端起固定数量的处理线程处理前端的任务,当处理线程处理完任务后从任务队列中获取下一个处理任务。保证了前端服务器端和后端服务器端的连接数不会超过前端服务器端的处理任务线程数 n ,从而保证了后端服务器端的压力。 当处理线程处理完一个任务而任务队列中没有任务的时候线程并不退出,阻塞等待新的任务。 通过上图可以看出,当前端服务器端通过设置合理的处理线程数和任务队列大小,可以有效的屏蔽前端客户端高并发量对后端服务器端的冲击。 2、 应用场景分析对比 a、 非线程池模型 适用于单次连接任务执行时间较长,并发量不高的情况。一旦并发量很高则线程频繁创建的开销是巨大的。

线程池入门

依然范特西╮ 提交于 2020-03-12 03:27:09
什么是池,我们在开发中经常会听到有线程池啊,数据库连接池等等。 那么到底什么是池? 其实很简单,装水的池子就叫水池嘛,用来装线程的池子就叫线程池(废话),就是我们把创建好的N个线程都放在一个池子里面,如果有需要,我们就去取,不用额外的再去手动创建了 为什么要用线程池 按照正常的想法是,我们需要一个线程,就去创建一个线程,这样的想法是没错的,但是如果需要有N多个线程呢?那把创建线程的代码复制N多份?或者用for循环来创建?NO,这样不是不行,但是不好。 因为线程也是有生命周期的,创建与销毁线程都会对系统资源有很大的开销,创建线程需要向系统申请相应的资源,销毁线程又会对垃圾回收器造成压力 使用线程池的好处 加快响应速度,需要线程我们就去取,不用额外的创建,可以反复利用。 合理的利用CPU与内存资源,因为CPU与内存都不是无限的 可以把线程进行一个统一的管理 线程池的适用场景 在实际开发中,如果需要5个以上的线程,那么就应该使用线程池来完成工作 线程池的创建与停止 我们先来说线程池的创建,我们都知道,在Java中的对象都是有构造方法的,有些可以使用无参的构造方法来创建,有些就需要使用有参的构造方法来创建,线程池的创建就必须要往构造方法中传入参数,我们就先来了解一下线程池中的构造参数都是一些什么含义吧,否则你怎么知道你创建的线程池是一个什么样的运行规则呢 corePoolSize:(int

线上问题排查,这些命令你一定用得到!

柔情痞子 提交于 2020-03-10 13:17:27
原文: 线上问题排查,这些命令你一定用得到! 一、了解机器连接数情况 问题:1.2.3.4的sshd的监听端口是22,如何统计1.2.3.4的sshd服务各种连接状态(TIME_WAIT/ CLOSE_WAIT/ ESTABLISHED)的连接数。 常见方法: netstat -n | grep 1.2.3.4:22 | awk '/^tcp/ {++S[$NF]} END {for(a in S) print a, S[a]}’ netstat -lnpta | grep ssh | egrep “TIME_WAIT | CLOSE_WAIT | ESTABLISHED” n [仅限于阿里云] 说明:netstat是追查网络连接问题常用工具,和grep/awk结合更是神器,当然如果在阿里云上,还有更方便的方法。 二、从已经备份好的日志中查询数据 问题:从已备份的suyun.2019-06-26.log.bz2日志中,找出包含关键字1.2.3.4的日志有多少条。 常见方法: bzcat suyun.2019-06-26.log.bz2 | grep '1.2.3.4' | wc -l bzgrep '1.2.3.4' suyun.2019-06-26.log.bz2 | wc -l less suyun.2019-06-26.log.bz2 | grep '10.37.9.11'

如何减少长时间的GC暂停?

流过昼夜 提交于 2020-03-08 21:12:41
长时间的GC暂停对于应用程序而言是不可取的。它会影响您的SLA,导致不良的客户体验,并对关键任务应用程序造成严重损害。因此,在本文中,我列出了可能导致长时间GC暂停的主要原因,以及解决这些问题的潜在解决方案。 1.高对象创造率 如果您的应用程序的对象创建率很高,那么为了跟上它,垃圾回收率也将很高。高垃圾回收率也会增加GC暂停时间。因此,优化应用程序以创建更少的对象是减少长时间GC暂停的有效策略。这可能是一个耗时的练习,但值得100%进行。为了优化应用程序中的对象创建速率,可以考虑使用Java Profiler(如 JProfiler, YourKit或JVisualVM)。这些分析器将报告:  创建了哪些对象?   这些对象的创建速率是多少?   它们在内存中占用多少空间?   谁在创造它们?  始终尝试优化占用最大内存量的对象。追捕池塘里的大鱼。 .年龄不足的年轻一代 当年轻一代过小时,对象会过早地提升到老一代。从年轻一代收集垃圾比从年轻一代收集垃圾要花费更多的时间。因此,增加年轻代的大小有可能减少长时间的GC暂停。可以通过设置两个JVM参数之一来增加年轻一代的大小 -Xmn:指定年轻代的大小。 -XX:NewRatio:指定年轻一代相对于老一代的大小。例如,设置-XX:NewRatio = 2表示老一代与年轻一代之间的比率为1:2。年轻一代将是整个堆的一半。因此

JUC并发编程(五):快速了解线程池

时光毁灭记忆、已成空白 提交于 2020-03-07 18:43:33
池化技术 首先我们要了解的一个东西就是程序运行的本质是占用系统资源! 所以我们为了提高程序的使用效率,降低我们的一个性能消耗,就要把一些频繁创建的资源提前给准备好,这就是池化技术. 常见的有线程池,连接池,内存池,对象池… 其次我们为什么要用线程池-- 多路复用 关于线程池,我们只要掌握三大方法,七大参数,四种拒绝策略即可!下 三大方法 newFixedThreadPool(),newCachedThreadPool(),newSingleThreadExecutor() public class Test1 { public static void main ( String [ ] args ) { //线程池 Executors原生三大方法 //固定大小 ExecutorService threadpool1 = Executors . newFixedThreadPool ( 5 ) ; //弹性收缩 ExecutorService threadpool2 = Executors . newCachedThreadPool ( ) ; //只有一个 ExecutorService threadpool3 = Executors . newSingleThreadExecutor ( ) ; try { for ( int i = 1 ; i <= 10 ; i ++ ) {

【Java】第四十二节 线程池

痞子三分冷 提交于 2020-03-06 14:03:08
一、为什么要用线程池 1、提高程序的执行效率 如果程序中有大量短时间任务的线程任务,由于创建和销毁线程需要和底层操作系统交互,大量时间都耗费在创建和销毁线程上,因而比较浪费时间,系统效率很低;线程池里的每一个线程任务结束后,并不会死亡,而是再次回到线程池中成为空闲状态,等待下一个对象来使用,因而借助线程池可以提高程序的执行效率。 2、控制线程的数量,防止程序崩溃 如果不加限制地创建和启动线程很容易造成程序崩溃,比如高并发1000W个线程,JVM就需要有保存1000W个线程的空间,这样极易出现内存溢出;线程池中线程数量是一定的,可以有效避免出现内存溢出。 二、常用方法 在JDK5之前,必须手动才能实现线程池,从JDK5开始新增了一个Executors工厂类,通过该工厂类可以实现线程池,该类有如下常用方法: public static ExecutorService newFixedThreadPool(int nThreads) :创建一个可重用的、具有固定线程数的线程池 public static ExecutorService newCachedThreadPool() :创建一个具有缓存功能的线程池,系统根据需要创建线程,这些线程将会被缓存在线程池中 public static ExecutorService newSingleThreadExecutor()

线程池

孤街醉人 提交于 2020-03-05 22:38:54
线程池优势: a、降低系统资源消耗,通过重用已存在的线程,降低线程创建和销毁造成的消耗; b、提高系统响应速度,当有任务到达时,通过复用已存在的线程,无需等待新线程的创建便能立即执行; c、方便线程并发数的管控。因为线程若是无限制的创建,可能会导致内存占用过多而产生OOM,并且会造成cpu过度切换(cpu切换线程是有时间成本的(需要保持当前执行线程的现场,并恢复要执行线程的现场)); d、提供更强大的功能,延时定时线程池; 线程池的主要参数: public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) { this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, Executors.defaultThreadFactory(), defaultHandler); } a、corePoolSize(线程池基本大小):当向线程池提交一个任务时,若线程池已创建的线程数小于corePoolSize,即便此时存在空闲线程,也会通过创建一个新线程来执行该任务

根据CPU核心数确定线程池并发线程数

浪尽此生 提交于 2020-03-05 17:46:53
一、抛出问题 关于如何计算并发线程数,一般分两派,来自两本书,且都是好书,到底哪个是对的?问题追踪后,整理如下: 第一派:《Java Concurrency in Practice》即《java并发编程实践》,如下图: 如上图,在《Java Concurrency in Practice》一书中,给出了估算线程池大小的公式: Nthreads=Ncpu*Ucpu*(1+w/c) ,其中 Ncpu=CPU核心数 Ucpu=cpu使用率,0~1 W/C=等待时间与计算时间的比率 第二派:《Programming Concurrency on the JVM Mastering》即《Java 虚拟机并发编程》 线程数=Ncpu/(1-阻塞系数) 二、分析 对于派系一,假设cpu100%运转,即撇开CPU使用率这个因素,线程数 =Ncpu*(1+w/c)。 现在假设将派系二的公式等于派系一公式,即 Ncpu/(1-阻塞系数)= Ncpu*(1+w/c) ,===》 阻塞系数=w/(w+c),即阻塞系数=阻塞时间/(阻塞时间+计算时间),这个结论在派系二后续中得到应征,如下图: 由此可见,派系一和派系二其实是一个公式......这样我就放心了...... 三、实际应用 那么实际使用中并发线程数如何设置呢?分析如下(我们以派系一公式为例): Nthreads=Ncpu*(1+w/c)

多线程进阶——JUC并发编程之Executors框架设计思想一探究竟🔥

浪子不回头ぞ 提交于 2020-03-01 16:55:31
1、学习切入点 Executors 框架是整个JUC 包中类/接口关系中最为复杂的框架,真正理解Executors框架的前提是理清楚各个模块之间的关系,高屋建瓴, 从整体到局部 才能透彻理解各个模块的功能和背后设计的思路! 本文将从 Executor、ExecutorService、ScheduledExecutorService、ThreadFactory和Callable 这些核心模块展开分析。 2、从Executor谈起 Executor 是JDK 1.5 时,随着JUC引入的一个接口,引入该接口的主要目的是 解耦任务本身和任务执行。我们之前通过线程执行一个任务时,往往需要先创建一个线程.satrt()去执行任务, 而Executor 接口解耦了任务和任务的执行,该接口只有一个方法,入参为待执行的任务。 public interface Executor { /** * 执行给定的Runable任务 * 根据Executor接口的实现类不同,具体执行方式也不同 */ void execute(Runnable command); } 我们可以像下面这样执行任务,而不必心线程的创建 Executor executor = anExecutor executor.execute(new RunnableTask1()); executor.execute(new