文章目录
- 运行时数据区域
- 问题引入
运行时数据区域
Java
虚拟机在执行Java
程序的过程中会把所管理的内存划分为若干个不同的数据区。运行时数据区包括了程序计数器、虚拟机栈、本地方法栈、方法区和堆
。
程序计数器
:程序计数器是线程私有
的内存,用来记住下一条指令的地址,字节码解释器(将指令解释为机器码,然后交给CPU
执行)通过改变计数器的值来选取下一条需要执行的指令。每条线程都有一个独立的程序计数器,各个计数器互不影响。(不会存在内存溢出问题)虚拟机栈
:是线程私有
的内存,虚拟机栈描述的是Java
方法执行的线程内存模型:每个方法被执行时Java
虚拟机栈都会创建一个栈帧
(方法运行时所需要的内存),存储局部变量表等信息(局部变量表存储了基本数据类型、对象引用和returnAddress类型)。每个方法被调用直至执行的过程就对应着一个栈帧从入栈
到出栈
的过程。本地方法栈
:虚拟机栈为执行Java
方法服务,本地方法栈为本地方法
服务。本地方法是一些用C
或C++
实现的方法,由于Java
语言无法直接跟底层的操作系统打交道,所以由Java
语言调用本地方法,由本地方法和操作系统交互。堆
:是所有线程共享
的内存区域,在虚拟机启动时创建。存储的是对象实例,几乎所有的对象实例
都在这里分配内存。堆中有垃圾回收机制。方法区
:是所有线程共享
的内存区域,存放的是被虚拟机加载的类型信息、常量、静态变量、即时编译器编译后的代码缓存等数据,在虚拟机启动时被创建。运行时常量池
:是方法区的一部分,存放编译器生成的各种字面量与符号引用,因为运行时常量池是方法区的一部分,所以就会受到内存的限制,当其无法在申请到内存时就会抛出OOM
异常。
问题引入
栈部分
:
垃圾回收是否涉及到栈内存?
不会,方法调用完之后会被自动弹出方法栈。
栈内存分配越大越好吗?
不是,栈内存分配的越大,每个线程所占的内存也就大,并发量越低。
方法内的局部变量是否线程安全?
如果是线程共享的,则考虑线程安全;如果是线程私有的,则不用考虑线程安全。
栈内存溢出(stack over flow
):
栈帧过多导致内存溢出,递归调用,方法自己调用自己。
栈帧过大导致内存溢出,不太常见
堆内存溢出(OutOfMemoryError
):
测试代码:
public static void main(String[] args) {
int i = 0;
List<String> list = new ArrayList<>();
String a = "hello";
try {
while (true){
list.add(a);
a = a+a;
i++;
}
}catch (Exception e){
e.printStackTrace();
System.out.println(i);
}
}
E:\JDK\bin\java.exe "-javaagent:E:\IDEA\IntelliJ IDEA 2020.2.3\lib\idea_rt.jar=59781:E:\IDEA\IntelliJ IDEA 2020.2.3\bin" -Dfile.encoding=UTF-8 -classpath E:\JDK\jre\lib\charsets.jar;E:\JDK\jre\lib\ext\access-bridge-64.jar;E:\JDK\jre\lib\ext\cldrdata.jar;E:\JDK\jre\lib\ext\dnsns.jar;E:\JDK\jre\lib\ext\jaccess.jar;E:\JDK\jre\lib\ext\jfxrt.jar;E:\JDK\jre\lib\ext\localedata.jar;E:\JDK\jre\lib\ext\nashorn.jar;E:\JDK\jre\lib\ext\sunec.jar;E:\JDK\jre\lib\ext\sunjce_provider.jar;E:\JDK\jre\lib\ext\sunmscapi.jar;E:\JDK\jre\lib\ext\sunpkcs11.jar;E:\JDK\jre\lib\ext\zipfs.jar;E:\JDK\jre\lib\jce.jar;E:\JDK\jre\lib\jfr.jar;E:\JDK\jre\lib\jfxswt.jar;E:\JDK\jre\lib\jsse.jar;E:\JDK\jre\lib\management-agent.jar;E:\JDK\jre\lib\resources.jar;E:\JDK\jre\lib\rt.jar;E:\ideaData\Design\out\production\Design com.jvm.MyJVM
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at java.util.Arrays.copyOf(Arrays.java:3332)
at java.lang.AbstractStringBuilder.ensureCapacityInternal(AbstractStringBuilder.java:124)
at java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:448)
at java.lang.StringBuilder.append(StringBuilder.java:136)
at com.jvm.MyJVM.main(MyJVM.java:14)
Process finished with exit code 1
堆内存诊断:
jps:
查看当前系统中有哪些Java进程
jmap:
查看堆内存占用情况
public class MyJVM {
public static void main(String[] args) throws InterruptedException {
System.out.println("1...");
Thread.sleep(30000);
byte[] array = new byte[1024*1024*10];
System.out.println("2...");
Thread.sleep(30000);
array = null;
System.gc();
System.out.println("3...");
Thread.sleep(1000000L);
}
}
E:\ideaData\Design>jmap -heap 13540
Attaching to process ID 13540, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 25.312-b07
using thread-local object allocation.
Parallel GC with 10 thread(s)
Heap Configuration:
MinHeapFreeRatio = 0
MaxHeapFreeRatio = 100
MaxHeapSize = 4118806528 (3928.0MB)
NewSize = 85983232 (82.0MB)
MaxNewSize = 1372585984 (1309.0MB)
OldSize = 171966464 (164.0MB)
NewRatio = 2
SurvivorRatio = 8
MetaspaceSize = 21807104 (20.796875MB)
CompressedClassSpaceSize = 1073741824 (1024.0MB)
MaxMetaspaceSize = 17592186044415 MB
G1HeapRegionSize = 0 (0.0MB)
Heap Usage:
PS Young Generation
Eden Space:
capacity = 65011712 (62.0MB)
used = 1300256 (1.240020751953125MB)
free = 63711456 (60.759979248046875MB)
2.000033470892137% used
From Space:
capacity = 10485760 (10.0MB)
used = 0 (0.0MB)
free = 10485760 (10.0MB)
0.0% used
To Space:
capacity = 10485760 (10.0MB)
used = 0 (0.0MB)
free = 10485760 (10.0MB)
0.0% used
PS Old Generation
capacity = 171966464 (164.0MB)
used = 1059248 (1.0101776123046875MB)
free = 170907216 (162.9898223876953MB)
0.6159619587223705% used
3127 interned Strings occupying 256408 bytes.
jconsole:
图形界面工具,多功能检测,可连续监测
输入命令 :jconsole