JVM读书笔记

深入理解java 虚拟机读书笔记

一、java虚拟机运行时数据区分一般为5种

1. 1 私有的部分包括

  1. 程序技术器:可以理解为当前线程所执行的字节码行数指示器,感觉和PC中的指    令寄存器类似
  2. 虚拟机栈 :描述java方法执行的内存模型,每个方法执行时都会生成栈帧用于存储局部变量表,操作数栈、方法链接等
  3. 本地方法栈:和虚拟机栈类似,但是为java虚拟机执行的本地方法

1.2 公有的部分

  1. 堆:为java虚拟机管理的最大一块内存,为所有线程共享,几乎所有的对象实例都在这里分配
  2. 方法区:为所有线程共享,存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码
  3. 运行时常量池 :它是方法区的一部分。用于存放编译期生成的各种字面量和符号引用, 在类加载后放入运行时常量池。

1.3 直接内存

直接内存不是虚拟机运行时数据区的一部分,也不是java 虚拟机规范中定义的内存区域。但是可以通过方法直接在内存中开辟空间进行使用。

二、类的创建过程

  虚拟机遇到一条new命令时,首先去检查这个指令的参数是否在常量池中定位到一个类 
  的符号引用,并检查这个符号引用说代表的类是否已被加载、解析和初始化、如果没有 
  必须先执行类的加载过程。

  类检查通过,接下来JVM为新生对象分配内存(对象所需内存大小在加载完之后便可确定 
  ),内存分配分为两种(1)指针碰撞(Bump the pointer)(2)空闲列表(Free List)。分配完成后虚拟机将分配的内存初始化为零值。

  接下来JVM 对对象进行必要的设置,例如对象是那个类的实例、如何才能找到类的元数 
  据信息、对象的hashCode 等这些存在对象头中(Object header)

三、对象的内存布局

3.1 对象内存中的数据结构

在HotSpot虚拟机中,对象在内存中存储的布局可以分为3块区域
  对象头    运行时数据, Mark Word
             类型指针
  实例数据
  对齐填充

3.2 对象的访问定位

java 程序通过栈上的reference 数据来操作堆上的具体对象。 分为两种句柄和直接指针

  1. 句柄在,内存中划分出一块内存来作为句柄池,reference中存储的就是对象的句柄地址,而句柄中包含了对象实例数据和类型数据各自的具体地址信息
  2. 直接指针, Java堆中存放存放对象的实例数据,其中包含到类型数据的指针,而reference 中包含的是对象地址

四、实战 OutOfMemoryError异常

 java堆溢出
  package chapter;

import java.util.ArrayList;
import java.util.List;

/**
 * VM args: -Xms20M -Xmx20m -XX:+HeapDumpOnOutOfMemoryError
 */
public class HeapDOM {
    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(Arrays.java:2245)
    at java.util.Arrays.copyOf(Arrays.java:2219)
    at java.util.ArrayList.grow(ArrayList.java:242)
    at java.util.ArrayList.ensureExplicitCapacity(ArrayList.java:216)
    at java.util.ArrayList.ensureCapacityInternal(ArrayList.java:208)
    at java.util.ArrayList.add(ArrayList.java:440)
    at chapter.HeapDOM.main(HeapDOM.java:18)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:606)
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140)

虚拟机栈和本地方法栈溢出

package chapter;

/**
 *VM Args:-Xss128K
 */
public class JavaVMStackSOF {
    private int stackLength= 1;

    public void statcKLeak() {
        stackLength ++;
        statcKLeak();
    }

    public static void main(String[] args)  throws Throwable{
        JavaVMStackSOF oom = new JavaVMStackSOF();
        try {
            oom.statcKLeak();
        } catch (Throwable e) {
            System.out.println("statck length:" + oom.stackLength);
            throw e;
        }
    }
}
statck length:11397
Exception in thread "main" java.lang.StackOverflowError
    at chapter.JavaVMStackSOF.statcKLeak(JavaVMStackSOF.java:10)
    at chapter.JavaVMStackSOF.statcKLeak(JavaVMStackSOF.java:11)
    at chapter.JavaVMStackSOF.statcKLeak(JavaVMStackSOF.java:11)
    at chapter.JavaVMStackSOF.statcKLeak(JavaVMStackSOF.java:11)
    at chapter.JavaVMStackSOF.statcKLeak(JavaVMStackSOF.java:11)

方法区和运行时常量池溢出

import java.util.ArrayList;
import java.util.List;

/**
 * VM Args:-XX:PermSize=10M -XX:MaxPermSize=10M
 */
public class RunTimeConstantPoolOOM {
    public static void main(String[] args) {
        List<String> list = new ArrayList<String>();

        int i = 0;
        while(true) {
            list.add(String.valueOf(i).intern());
        }

    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值