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。
被所有线程共享

/**
 * 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(); // 调用此命令后,新生代被清空
    }
}
[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]
# 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
 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错误:

[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]
作者:张三  创建时间:2024-12-26 19:43
最后编辑:张三  更新时间:2025-03-07 21:22