1、栈上分配、逃逸分析
2、四种引用
软引用:一个对象只持有软引用,那么当堆空间不足时,就会被回收
弱引用:在系统 GC 时,只要发现弱引用,不管系统堆空间使用情况如何,都会将对象进行回收。但是,由于垃圾回收器的线程通常优先级很低,因此,并不一定能很快地发现持有弱引用的对象。在这种情况下,弱引用对象可以存在较长的时间。
软引用 、弱引用 都非常适合来保存那些可有可无的缓存数据。 如果这么做,当系统内存不足时,这些缓存数据会被回收,不会导致内存溢出 。 而当内存资源充足时,这些缓存数据又可以存在相当长的时间,从而起到加速系统的作用 。
虚引用必须和引用队列一起使用,它的作用在于跟踪垃圾回收过程
为什么需要 TLAB 这个区域呢?这是为了加速对象分配而生的 。 由于对象一般会分配在堆上,而堆是全局共享的 。 因此在同一时间,可能会有多个线程在堆上申请空间 。 因此,每一次对象分配都必须要进行同步,而在竞争激烈的场合分配的效率又会进一步下降。
Linux 下的性能监控工具
显示系统整体资源使用情况一一top 命令
V i s u a l VM 也支持远程川X 连接
Thread Dump 和分析
内存快照分析
Arthas
fastthread.io https://developer.aliyun.com/article/1149635
JVM 参数
官网全量参数文档:https://docs.oracle.com/en/java/javase/14/docs/specs/man/java.html
Thread.currentThread().interrupt()
对线面试官系列
该播主除了一些不错的文章,推荐关注。
为什么需要Java内存模型?
Java从编译到执行,发生了什么?
双亲委派机制
深入浅出 Java 内存模型
JVM内存结构
垃圾回收机制
CMS垃圾回收器
G1垃圾收集器
JVM调优
heapdump 系列
JVM虚拟机 这个博主整理了不少好文章
JVM性能调优监控工具专题一:JVM自带性能调优工具(jps,jstack,jmap,jhat,jstat,hprof)
jps [options] [hostid]
使用jps查看出当前有哪些Java进程,获取该Java进程的id
-q 不输出类名、Jar名和传入main方法的参数
-m 输出传入main方法的参数
-l 输出main类或Jar的全限名
-v 输出传入JVM的参数
jstack
jstack主要用来查看某个Java进程内的线程堆栈信息。
jstack [option] pid
jstack [option] executable core
jstack [option] [server-id@]remote-hostname-or-ip
命令行参数选项说明如下:
-l long listings,会打印出额外的锁信息,在发生死锁时可以用jstack -l pid来观察锁持有情况
-m mixed mode,不仅会输出Java堆栈信息,还会输出C/C++堆栈信息(比如Native方法)
jstack可以定位到线程堆栈,根据堆栈信息我们可以定位到具体代码,所以它在JVM性能调优中使用得非常多。
jmap(Memory Map)和 jhat(Java Heap Analysis Tool):
jmap导出堆内存,然后使用jhat来进行分析
jmap用来查看堆内存使用状况,一般结合jhat使用。
jmap [option] pid
jmap [option] executable core
jmap [option] [server-id@]remote-hostname-or-ip
- 打印进程的类加载器和类加载器加载的持久代对象信息: jmap -permstat pid
- 查看进程堆内存使用情况:包括使用的GC算法、堆配置参数和各代中堆内存使用:jmap -heap pid
- 查看堆内存中的对象数目、大小统计直方图,如果带上live则只统计活对象:jmap -histo[:live] pid
- 用jmap把进程内存使用情况dump到文件中,再用jhat分析查看。需要注意的是 dump出来的文件还可以用MAT、VisualVM等工具查看。
jmap -dump:format=b,file=dumpFileName pid
jmap -dump:format=b,file=/home/dump.dat
jhat -port 8888 /home/dump.dat
jstat(JVM统计监测工具): 看看各个区内存和GC的情况
jstat [ generalOption | outputOptions vmid [interval[s|ms] [count]] ]
vmid是Java虚拟机ID,在Linux/Unix系统上一般就是进程ID。
interval是采样时间间隔。
count是采样数目。
比如下面输出的是GC信息,采样时间间隔为250ms,采样数为6
jstat -gc 2860 250 6
要明白上面各列的意义,先看JVM堆内存布局
可以看出:
堆内存 = 年轻代 + 年老代 + 永久代
年轻代 = Eden区 + 两个Survivor区(From和To)
现在来解释各列含义:
S0C、S1C、S0U、S1U:Survivor 0/1区容量(Capacity)和使用量(Used)
EC、EU:Eden区容量和使用量
OC、OU:年老代容量和使用量
PC、PU:永久代容量和使用量
YGC、YGT:年轻代GC次数和GC耗时
FGC、FGCT:Full GC次数和Full GC耗时
GCT:GC总耗时
hprof(Heap/CPU Profiling Tool): hprof能够展现CPU使用率,统计堆内存使用情况。
HPROF: 一个Heap/CPU Profiling工具:J2SE中提供了一个简单的命令行工具来对java程序的cpu和heap进行 profiling,叫做HPROF。HPROF实际上是JVM中的一个native的库,它会在JVM启动的时候通过命令行参数来动态加载,并成为 JVM进程的一部分。若要在java进程启动的时候使用HPROF,用户可以通过各种命令行参数类型来使用HPROF对java进程的heap或者 (和)cpu进行profiling的功能。HPROF产生的profiling数据可以是二进制的,也可以是文本格式的。这些日志可以用来跟踪和分析 java进程的性能问题和瓶颈,解决内存使用上不优的地方或者程序实现上的不优之处。二进制格式的日志还可以被JVM中的HAT工具来进行浏览和分析,用 以观察java进程的heap中各种类型和数据的情况。在J2SE 5.0以后的版本中,HPROF已经被并入到一个叫做Java Virtual Machine Tool Interface(JVM TI)中。
java -agentlib:hprof[=options] ToBeProfiledClass
java -Xrunprof[:options] ToBeProfiledClass
javac -J-agentlib:hprof[=options] ToBeProfiledClass
完整的命令选项如下:
Option Name and Value Description Default
heap=dump|sites|all heap profiling all
cpu=samples|times|old CPU usage off
monitor=y|n monitor contention n
format=a|b text(txt) or binary output a
file= write data to file java.hprof[.txt]
net=: send data over a socket off
depth= stack trace depth 4
interval= sample interval in ms 10
cutoff= output cutoff point 0.0001
lineno=y|n line number in traces? y
thread=y|n thread in traces? n
doe=y|n dump on exit? y
msa=y|n Solaris micro state accounting n
force=y|n force output to y
verbose=y|n print messages about dumps y
使用jstack来分析死锁问题
继续使用jstack来分析HashMap在多线程情况下的死锁问题
java内存管理深入浅出
讲述了:
- Java如何管理内存
- 内存泄漏以及内存区域的组成
- 内存中数据是如何存储的(基本数据类型、字符串、类等)
- 内存管理机制和垃圾回收机制
- final问题
- 如何把程序写得更健壮
- 尽早释放无用对象的引用
- 定义字符串应该尽量使用String str=”hello”;的形式,避免使用String str = new String(“hello”);的形式
- 大量使用字符串处理时,避免使用String,应大量使用StringBuffer
- 尽量少用静态变量,因为静态变量是全局的,GC不会回收的;
- 尽量避免在类的构造函数里创建、初始化大量的对象,防止在调用其自身类的构造器时造成不必要的内存资源浪费,尤其是大对象,JVM会突然需要大量内存,这时必然会触发GC优化系统内存环境;显示的声明数组空间,而且申请数量还极大。
- 在合适的场景下使用对象池技术以提高系统性能,缩减缩减开销
- 大集合对象拥有大数据量的业务对象的时候,可以考虑分块进行处理,然后解决一块释放一块的策略。
- 不要在经常调用的方法中创建对象,尤其是忌讳在循环中创建对象。
- 一般都是发生在开启大型文件或跟数据库一次拿了太多的数据,造成Out Of Memory Error的状况
- 尽量少用finalize函数,因为finalize()会加大GC的工作量,而GC相当于耗费系统的计算能力。
- 不要过滥使用哈希表,有一定开发经验的开发人员经常会使用hash表(hash表在JDK中的一个实现就是HashMap)来缓存一些数据,从而提高系统的运行速度。比如使用HashMap缓存一些物料信息、人员信息等基础资料,这在提高系统速度的同时也加大了系统的内存占用,特别是当缓存的资料比较多的时候。其实我们可以使用操作系统中的缓存的概念来解决这个问题,也就是给被缓存的分配一个一定大小的缓存容器,按照一定的算法淘汰不需要继续缓存的对象,这样一方面会因为进行了对象缓存而提高了系统的运行效率,同时由于缓存容器不是无限制扩大,从而也减少了系统的内存占用。现在有很多开源的缓存实现项目,比如ehcache、oscache等,这些项目都实现了FIFO 、MRU等常见的缓存算法。
JVM性能监控与故障处理
- BTrace动态日志跟踪
通过BTrace可以打印调用堆栈、参数、返回值,还可以进行性能监视、定位连接泄漏、内存泄漏、解决多线程竞争问题。
HotSwap技术:代码热替换技术,HotSpot虚拟机允许在不停止运行的情况下,更新已经加载的类的代码。