了解 JVM 内存结构的目的
在 Java 的开发过程中, 因为有 JVM 自动内存管理机制, 不再需要像在 C,C++ 开发那样手动释放对象的内存空间, 不容易出现内存泄漏和内存溢出的问题. 但是, 正是由于把内存管理的权利交给了 JVM, 一旦出现内存泄漏和内存溢出方面的问题, 如果不了解 JVM 是如何使用内存的, 不了解 JVM 的内存结构是什么样子的, 就很难找到问题的根源, 就更难以解决问题.
JVM 内存结构简介
在 JVM 所管理的内存中, 大致分为以下几个运行时数据区域:
程序计数器: 当前线程所执行的字节码的行号指示器.
虚拟机栈: Java 方法执行的内存模型, 用于存储局部变量表, 操作数栈, 动态链接, 方法出口等信息.
本地方法栈: 本地方法执行的内存模型, 和虚拟机栈非常相似, 其区别是本地方法栈为 JVM 使用到的 Native 方法服务.
堆: 用于存储对象实例, 是垃圾收集器管理的主要区域.
方法区: 用于存储已被 JVM 加载的类信息, 常量, 静态变量, 即时编译器编译后的代码等数据.
其中, 黄色区域的程序计数器, 虚拟机栈和本地方法栈是线程私有的, 红色区域的堆和方法区是线程共享的. 下面我们逐一详细分析各个区域.
- /**
- * VM Args: -Xss128k
- */
- public class JVMStackSOF {
- private int stackLength = 1;
- public void stackLeak() {
- stackLength++;
- stackLeak();
- }
- public static void main(String[] args) {
- JVMStackSOF sof = new JVMStackSOF();
- try {
- sof.stackLeak();
- } catch (Throwable e) {
- System.out.println("Stack length:" + sof.stackLength);
- throw e;
- }
- }
- }
- Stack length:1002
- Exception in thread "main" java.lang.StackOverflowError
- at OneMoreStudy.JVMStackSOF.stackLeak(JVMStackSOF.java:10)
- at OneMoreStudy.JVMStackSOF.stackLeak(JVMStackSOF.java:11)
- at OneMoreStudy.JVMStackSOF.stackLeak(JVMStackSOF.java:11)
- ......
- /**
- * VM Args: -Xss2M
- */
- public class JVMStackOOM {
- private void dontStop() {
- while (true) {
- }
- }
- public void stackLeakByThread() {
- while (true) {
- Thread t = new Thread(new Runnable() {
- public void run() {
- dontStop();
- }
- });
- t.start();
- }
- }
- public static void main(String[] args) {
- JVMStackOOM oom = new JVMStackOOM();
- oom.stackLeakByThread();
- }
- }
- Exception in thread "main" java.lang.OutMemoryError: unable to create new native thread
- at java.lang.Thread.start0(Native Method)
- at java.lang.Thread.start(Unknown Source)
- at OneMoreStudy.JVMStackOOM.stackLeakByThread(JVMStackOOM.java:18)
- at OneMoreStudy.JVMStackOOM.main(JVMStackOOM.java:24)
- /*
- * VM Args: -Xms20M -Xmx20M
- */
- public class HeapOOM {
- static class OOMObject{
- }
- public static void main(String[] args){
- List<OOMObject> list = new ArrayList<OOMObject>();
- while(true){
- // 把对象实例放入列表中,
- // 使其一直被引用, 不会被垃圾回收
- list.add(new OOMObject());
- }
- }
- }
- Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
- at java.util.Arrays.copyOf(Unknown Source)
- at java.util.Arrays.copyOf(Unknown Source)
- at java.util.ArrayList.grow(Unknown Source)
- at java.util.ArrayList.ensureExplicitCapacity(Unknown Source)
- at java.util.ArrayList.ensureCapacityInternal(Unknown Source)
- at java.util.ArrayList.add(Unknown Source)
- at OneMoreStudy.HeapOOM.main(HeapOOM.java:18)
- /*
- * VM Args: -XX:PermSize=2M -XX:MaxPermSize=2M
- */
- public class RuntimeConstantPoolOOM {
- public static void main(String[] args) {
- List<String> list = new ArrayList<String>();
- for (int i = 0; i < 100000; i++) {
- System.out.println(i);
- // 将 i 转化为字符串,
- // 并且调用 intern(), 把字符串放在运行时常量池
- list.add(String.valueOf(i).intern());
- }
- }
- }
- ......
- 35813
- 35814
- Exception in thread "main" java.lang.OutOfMemoryError: PermGen space
- at java.lang.String.intern(Native Method)
- at OneMoreStudy.RuntimeConstantPoolOOM.main(RuntimeConstantPoolOOM.java:12)
- ......
- 99996
- 99997
- 99998
- 99999
- /*
- * VM Args: -XX:PermSize=2M -XX:MaxPermSize=2M
- */
- public class MethodAreaOOM {
- static class OOMObject {
- }
- public static void main(String[] args) {
- for (int i = 0; i < 300; i++) {
- System.out.println(i);
- createNewClass();
- }
- }
- private static void createNewClass() {
- // 这里使用了 CGLIB, 动态创建类, 载入方法区
- Enhancer enhancer = new Enhancer();
- enhancer.setSuperclass(OOMObject.class);
- enhancer.setUseCache(false);
- enhancer.setCallback(new MethodInterceptor() {
- @Override
- public Object intercept(Object obj, Method method,
- Object[] args, MethodProxy proxy) throws Throwable {
- return proxy.invokeSuper(obj, args);
- }
- });
- enhancer.create();
- }
- }
- ......
- Caused by: java.lang.OutOfMemoryError: PermGen space
- at java.lang.ClassLoader.defineClass1(Native Method)
- at java.lang.ClassLoader.defineClassCond(Unknown Source)
- at java.lang.ClassLoader.defineClass(Unknown Source)
- ... 12 more
- Exception in thread "main"
- Exception: java.lang.OutOfMemoryError thrown from the UncaughtExceptionHandler in thread "main"
- ......
- 298
- 299
- Java HotSpot(TM) 64-Bit Server VM warning: ignoring option PermSize=2M; support was removed in 8.0
- Java HotSpot(TM) 64-Bit Server VM warning: ignoring option MaxPermSize=2M; support was removed in 8.0
来源: https://www.cnblogs.com/heihaozi/p/12118146.html