java
标准化、规范化
java代码风格
【目录】java
编程-java8
编程-java9
编程-java-见过的异常
gradle
编程-java21
编程-java23
编程-java17
编程-java11
【目录】java-web-其它框架
java-vertx
quarkus
javalin
solon
Helidon
【目录】spring家族
spring
springcloud + nacos
consul
springboot启动流程
springboot使用及原理
springcloud
优化springboot
【java高级】
java-多线程-问题记录
java高级-ArrayList
java高级-HashMap
jdk源码解析-TreeMap红黑树
java对象占用多少字节
juc(并发)
ThreadPoolExecutor中ctl变量的理解
ThreadPoolExecutor分析
JVM(java虚拟机)
jvm学习路线
jvm
Java启动参数
debug
java-debug-arthas
java-debug-jdb
高并发/高性能/高可用
设计代码或编写代码时应该考虑的
如何发现系统中的瓶颈?
场景分析
mysql
mysql explain
mysql主从
mysql常见异常
方法论
工作中遇到的问题记录
代码优化
学习的思路
产品
本文档使用 MrDoc 发布
-
+
首页
jvm
# jvm ## 内存结构 oom: OutOfMemoryError soe: StackOverflowError TODO 整理各个区域的异同 TODO 整理OOM后面各种错误信息 - unable to create new native thread 是否会oom,是否会soe 是否线程私有/线程共享 是否会垃圾回收 | 区域 | 是否会OutOfMemory | 是否会StackOverflowError | 是否会gc | | --- | --- | --- |--- | | 程序计数器 | N | N | N | | 本地方法栈 | Y | Y | N | | 虚拟机栈 | Y | Y | N | | java堆 | Y | Y | Y | | 方法区 | Y| Y | Y | ### 程序计数器(Program Counter Register) 用于记录下一条要运行的指令的地址。是线程私有的内存空间。 (若当前线程正在执行一个java方法,程序计数器记录的是正在执行的java字节码地址,若当前线程正在执行一个native方法,则为undefined) 此内存区域不会发生OutOfMemoryError。 ### 虚拟机栈 是线程私有的内存空间。 此内存区域会发生StackOverflowError和OutOfMemoryError。 -Xss 栈帧:方法在被调用时的一种数据结构,存放了方法的局部变量表、操作数栈、动态连接方法、返回地址、其它信息。 局部变量表中,long/double占用64位,其它类型(byte,short,char,int,float,对象引用)占32位。 局部变量表是GC Roots之一。 ### 本地方法栈 本地方法是用C/C++实现的。 此内存区域会发生StackOverflowError和OutOfMemoryError。 ### java堆 堆空间分为新生代和老年代。 新生代又分为Eden/survior0/survior1。 被所有线程共享 ```java /** * java8中 * -XX:+PrintGCDetails -XX:SurvivorRatio=8 -XX:MaxTenuringThreshold=15 -Xms40M -Xmx40M -Xmn20M */ public class ObjectWasCreateAtEden { final static int _1M = 1024 * 1024; public static void main(String[] args) { byte[] b1 = new byte[_1M / 10]; byte[] b2 = new byte[_1M * 10]; b2 = null; b2 = new byte[_1M * 8]; System.gc(); // 调用此命令后,新生代被清空 } } ``` ```text [GC (System.gc()) [PSYoungGen: 14280K->1345K(18432K)] 22472K->9545K(38912K), 0.0033214 secs] [Times: user=0.00 sys=0.00, real=0.00 secs] [Full GC (System.gc()) [PSYoungGen: 1345K->0K(18432K)] [ParOldGen: 8200K->9450K(20480K)] 9545K->9450K(38912K), [Metaspace: 3322K->3322K(1056768K)], 0.0128114 secs] [Times: user=0.01 sys=0.00, real=0.02 secs] Heap PSYoungGen total 18432K, used 164K [0x00000000fec00000, 0x0000000100000000, 0x0000000100000000) eden space 16384K, 1% used [0x00000000fec00000,0x00000000fec290d0,0x00000000ffc00000) from space 2048K, 0% used [0x00000000ffc00000,0x00000000ffc00000,0x00000000ffe00000) to space 2048K, 0% used [0x00000000ffe00000,0x00000000ffe00000,0x0000000100000000) ParOldGen total 20480K, used 9450K [0x00000000fd800000, 0x00000000fec00000, 0x00000000fec00000) object space 20480K, 46% used [0x00000000fd800000,0x00000000fe13aa48,0x00000000fec00000) Metaspace used 3332K, capacity 4496K, committed 4864K, reserved 1056768K class space used 363K, capacity 388K, committed 512K, reserved 1048576K ``` ### 方法区 HotSpot中称方法区为永久区。 所有线程共享该区域。 方法区主要保存的是类的元数据、常量池、方法信息。 对方法区GC的回收,从如下两个方面: - 对常量池的回收 (String#intern()) - 对类元数据的回收 (两个条件:一个类的所有实例已被回收,加载该类的ClassLoader也已被回收) ## 类加载 ## GC (garbage collection) ### GC在jvm中的应用 ### 命令 - jps -lvVm - jstack $pid [ > c:/tmp/web-tester-stack.log ] - jmap -histo $pid [ > c:/tmp/map.log] - 如何知道eden s0 s1 old的大小? `jmap -heap $pid [ > c:/tmp/map.log]` ```text # jmap -heap 2696或者jhsdb jmap --heap --pid 2696 Attaching to process ID 2696, please wait... Debugger attached successfully. Server compiler detected. JVM version is 21.0.6+8-LTS-jvmci-23.1-b55 using thread-local object allocation. Garbage-First (G1) GC with 13 thread(s) Heap Configuration: MinHeapFreeRatio = 40 MaxHeapFreeRatio = 70 MaxHeapSize = 209715200 (200.0MB) NewSize = 1363144 (1.2999954223632812MB) MaxNewSize = 125829120 (120.0MB) OldSize = 5452592 (5.1999969482421875MB) NewRatio = 2 SurvivorRatio = 8 MetaspaceSize = 22020096 (21.0MB) CompressedClassSpaceSize = 1073741824 (1024.0MB) MaxMetaspaceSize = 17592186044415 MB G1HeapRegionSize = 1048576 (1.0MB) Heap Usage: G1 Heap: regions = 200 capacity = 209715200 (200.0MB) used = 75363072 (71.871826171875MB) free = 134352128 (128.128173828125MB) 35.9359130859375% used G1 Young Generation: Eden Space: regions = 2 capacity = 131072000 (125.0MB) used = 2097152 (2.0MB) free = 128974848 (123.0MB) 1.6% used Survivor Space: regions = 0 capacity = 1048576 (1.0MB) used = 14448 (0.0137786865234375MB) free = 1034128 (0.9862213134765625MB) 1.37786865234375% used G1 Old Generation: regions = 76 capacity = 77594624 (74.0MB) used = 73251472 (69.85804748535156MB) free = 4343152 (4.1419525146484375MB) 94.4027668720967% used ``` - jmap -dump:file=c:/tmp/web-tester.bin $pid - 查看gc相关 `jstat -gcutil $pid` ```text jstat -gcutil 2696 1000 S0 S1 E O M CCS YGC YGCT FGC FGCT CGC CGCT GCT - 1.57 2.56 99.75 98.35 93.88 187 0.342 1 0.029 4 0.006 0.376 - 1.97 0.80 87.56 98.35 93.88 188 0.344 1 0.029 4 0.006 0.378 - 1.97 0.80 87.56 98.35 93.88 188 0.344 1 0.029 4 0.006 0.378 - 1.97 0.80 87.56 98.35 93.88 188 0.344 1 0.029 4 0.006 0.378 - 1.97 1.60 87.56 98.35 93.88 188 0.344 1 0.029 4 0.006 0.378 - 1.97 1.60 87.56 98.35 93.88 188 0.344 1 0.029 4 0.006 0.378 //S0 — 年轻代中第一个survivor(幸存区)已使用的占当前容量百分比 //S1 — 年轻代中第二个survivor(幸存区)已使用的占当前容量百分比 //E — 年轻代中Eden(伊甸园)已使用的占当前容量百分比 //O — Heap上的 Old space 区已使用空间的百分比 //P — Perm space 区已使用空间的百分比 YGC: 年轻代垃圾回收次数 YGCT: 年轻代垃圾回收消耗的时间 (秒) FGC: 老年代垃圾回收次数 FGCT: 老年代垃圾回收消耗的时间 (秒) CGC: 压缩类空间垃圾回收次数 CGCT: 压缩类空间垃圾回收消耗的时间 (秒) GCT: 总的垃圾回收消耗的时间 (秒) ``` - jstat -gc PID 1000 10 (每秒查看一次gc信息,共10次) - 查看运行中的jvm的启动参数 #### Java VisualVM - 如何查看一个运行中的java进程的Xss参数。 jinfo -flag ThreadStackSize pid (可尝试启动一个java进程添加-Xss2m来测试,我jdk-1.8.0_121启动一个简单的没有配置任何Xss的main方法,该值是0)-Xss is translated in a VM flag named ThreadStackSize -XX:+UseParNewGC -XX:+CMSParallelRemarkEnabled -XX:+UseConcMarkSweepGC -XX:CMSInitiatingOccupancyFraction=75,网上有提到JVM提供了3种垃圾收集器,如果是长生命周期(老年代)对象较多时可以使用CMS收集器。 #### jvm内存分配参数 win7 x64 jdk-8u121上使用如下参数 -XX:+PrintGC -XX:+PrintGCDetails -XX:+PrintHeapAtGC -Xmx32M -Xms32M -Xloggc:c:/tmp/gclog/forgc1.log -XX:+PrintVMOptions -XX:+PrintFlagsFinal -XX:+TraceClassLoading -XX:+TraceClassUnloading -XX:SurvivorRatio=8 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=c:/tmp/gclog/haep.dump loggc中显示CommandLine flags: -XX:+PrintGC -XX:+PrintGCDetails -XX:+PrintHeapAtGC -Xmx32M -Xms32M -Xloggc:c:/tmp/gclog/forgc1.log -XX:+PrintVMOptions -XX:+PrintFlagsFinal -XX:+TraceClassLoading -XX:+TraceClassUnloading -XX:SurvivorRatio=8 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=c:/tmp/gclog/haep.dump - -Xms --> -XX:InitialHeapSize 最小堆 - -Xmx --> -XX:MaxHeapSize 最大堆 - -XX:MinHeapFreeRatio 堆空间的最小空闲比例,当堆空间的空闲内存小于这个数值时,jvm便会扩展堆空间 - -XX:MaxHeapFreeRatio 堆空间的最大空闲比例,当堆空间的空闲内存大于这个数值时,jvm便会压缩堆空间 - -Xss 设置线程栈大小 - -Xmn 设置新生代的大小,该参数的效果等同于设置了-XX:NewSize和-XX:MaxNewSize,如-Xmn100M (-XX:MaxNewSize=10485760 -XX:NewSize=10485760) - -XX:NewSize=11010048 -XX:MaxNewSize=11010048 为-Xmx的1/3 - -XX:+PrintFlagsFinal - Eden与s0s1的空间会动态变化 - -XX:PermSize和-XX:MaxPermSize用来设置永久代的初始和最大值 - 堆的比例分配-XX:SurvivorRatio用来设置新生代中eden与s0空间的比例,-XX:SurvivorRatio=eden/s0=eden/s1 - -XX:NewRatio 老年代/新生代的比率,默认是2,所以就有了下面的NewSize为1/3 - -XX:TargetSurviorRatio 设置survior区的可使用率,当使用率达到该数值时,会将对象送入老年代。 -XX:PretenureSizeThreshold 当新创建的对象大小超过此值时会直接在老年代分配 -XX:+DisableExplicitGC 禁用显式GC(即System.gc()) gc调优,即是尽可能将对象预留在新生代,减少老年代gc的次数 ### 引用 | 引用类型 | 是否会被回收 | --- | | --- | --- | --- | | 强引用 | 不会 | --- | | 软引用 | 内存不够时会 | --- | | 弱引用 | 会 | --- | | 虚引用 | 会 | --- | 关闭windows的虚拟内存会导致内存不够用,进而会导致idea出现jvm错误: ```text [thread 8996 also had an error] # # There is insufficient memory for the Java Runtime Environment to continue. # Native memory allocation (malloc) failed to allocate 32744 bytes for ChunkPool::allocate # An error report file with more information is saved as: # D:\shigoto\code\datatist-wolf\hs_err_pid8316.log [thread 8768 also had an error] [thread 4352 also had an error] [error occurred during error reporting , id 0xe0000001] ```
我是张三
2025年3月7日 21:22
转发文档
收藏文档
上一篇
下一篇
手机扫码
复制链接
手机扫一扫转发分享
复制链接
eblog
Markdown文件
分享
链接
类型
密码
更新密码