[总结]-第二章 Java内存区域与内存溢出异常

[总结]-第二章 Java内存区域与内存溢出异常

1、知识点

一、虚拟机运行时数据区

  • 方法区:运行时常量池(JDK1.7被移出)
  • 堆:存放对象实例或数组新生代和老年代
  • 虚拟机栈:线程私有
  • 本地方法栈:线程私有Native
  • 程序计数器:线程私有行号指示器无OOM

字节码解释器工做时就是经过改变程序计数器的值来选取下一条须要执行的字节码指令。java

二、Java堆的内存分配方式

  • 指针碰撞(内存规整)
  • 空闲列表(内存不规整)

选择哪一种分配方式由Java堆是否规整决定,而Java堆是否规整又由所采用的垃圾收集器是否带有压缩整理功能决定。数组

三、对象的内存布局

  • 对象头
    • 对象自身运行时数据(Mark Word) - 若是32bit
      • 哈希码(25bit)[未锁定时]
      • GC分代年龄(4bit)[未锁定时]
      • 锁状态标志位(2bit)
        • 01 未锁定 [未锁定时]
        • 01 偏向锁 [锁定时]
        • 00 轻量级锁 [锁定时]
        • 10 重量级锁 [锁定时]
        • 11 GC标记
      • 固定为0(1bit)
    • 类型指针:对象指向它的类元数据的指针,虚拟机经过这个指针判断此对象是哪一个类的实例。
  • 实例数据:程序代码中定义的各类类型的字段内容。
  • 对齐填充:仅仅是占位符。

四、对象的访问定位

  • 使用句柄 -> 句柄池安全

    • reference中存储的就是对象的句柄地址
    • 好处:reference中存储的是稳定的句柄地址,在对象被移动(GC时移动)时只会改变句柄中的实例数据指针,而reference自己不须要修改。
  • 直接指针微信

    • reference中存储的直接就是对象地址
    • 好处:速度更快,节省一次指针定位的时间开销。

2、名词解释

  1. JIT编译器:Just in time compiler 即时编译器;
  2. 字面量:文本字符串,声明为final的常量池;
  3. 符号引用:类和接口的全限定名(包名+类名)、字段的名称和描述符、方法的名称和描述符;
  4. 偏向锁:是指一段同步代码一直被一个线程所访问,那么该线程会自动获取锁,下降获取锁的代价;
  5. CAS:Compare And Swap 比较交换;
  6. 逃逸分析:开启逃逸分析,直接栈上分配;

3、常见问题:

一、程序计数器为何不会内存溢出?

由于程序计数器中存储的数据所占空间的大小不会随着程序的执行而发生改变。多线程

二、intern()的使用?

JDK1.6在常量池建立与此String内容相同的字符串;常量池 建立字符串->返回引用 JDK1.7在常量池中记录Heap中首次出现的引用,并返回该引用。常量池 记录引用->返回引用app

String str1 = new StringBuilder("计算机").append("软件").toString();
System.out.println((str1.intern() == str1));
//JDK1.6:false
//JDK1.7:true

三、String s = new String("你好");建立了几个对象?

  • 直接使用双引号声明出来的String对象会直接存储在常量池
  • 使用new,JVM会在中建立一个内容相同的String对象,而后返回堆中String对象的引用。

四、内存分配怎么解决线程安全问题?

  • 对分配内存空间的动做进行同步处理-采用CAS配上失败重试的方式保证更新操做的原子性;
  • 把内存分配的动做按照线程划分在不一样的空间之中进行,即每一个线程在Java堆中预先分配一小块内存,称为本地线程分配缓冲(TLAB)

五、CAS是什么?

CAS(Compare And Swap 比较交换),是无锁执行者,能够用来保证线程执行的安全性。核心思想以下:函数

执行函数:CAS(V,E,N)

其包含3个参数布局

  • V 表示要更新的变量
  • E 表示预期值
  • N 表示新值

若是V值等于E值,则将V的值设为N。若V值和E值不一样,则说明已经有其余线程作了更新,此时当前线程不执行更新操做,但能够选择从新读取该变量再尝试再次修改该变量,也能够放弃操做。ui

CAS是一条CPU的原子指令,完成某个功能的一个过程的原语的执行必须是连续的,不会形成所谓的数据不一致问题。spa

六、字节与byte与bit的关系

1 字节 = 1 byte = 8 bit

七、如何避免堆自动扩展?

将堆的最小值-Xms参数与最大值-Xmx参数设置为同样便可避免堆自动扩展。

八、常见OOM有哪些?分别怎么分析定位?

java.lang.OutOfMemoryError: Java heap space

堆内存溢出(最多见的),能够Dump堆转储快照信息查看具体问题。

java.lang.StackOverflowError

虚拟机栈内存溢出 - 超出当前方法栈深度

java.lang.OutOfMemoryError: unable to create new native thread

多线程致使内存溢出,可经过“减小最大堆”和“减小栈容量”来换取更多的线程。

java.lang.OutOfMemoryError: PermGen space

出现这个异常说明运行时常量池属于方法区的一部分,能够手动设置MaxPermSize大小修改。 jdk1.7已经将常量池从方法区移出,jdk1.8彻底删除永久代,全部jdk1.8不会出现此OOM。

java.lang.OutOfMemoryError

由DirectMemory(本机直接内存)致使的OOM,没有明显的异常说明,由于这里的内存不足时它自己计算出来,并手动抛出异常。

4、常见命令

-XX:+HeapDumpOnOutOfMemoryError

可让虚拟机在出现OOM时Dump出当前的内存堆转储快照以便过后进行分析

-Server -XX:+DoEscapeAnalysis

开启逃逸分析,直接栈上分配

-XX:MaxDirectMemorySize

指定本机直接内存容量,默认为java堆最大值-Xmx

博客

https://my.oschina.net/gmarshal

欢迎关注个人我的微信订阅号:(听说这个头像程序猿专用)

输入图片说明

相关文章
相关标签/搜索