Java运行时内存分配总结

2019-02-15  本文已影响0人  Weechan_

程序计数器

当前线程执行字节码行号指示器
每个线程都有一个计数器,是线程私有的。

JAVA虚拟机栈

存储方法调用创建的栈帧,执行方法栈帧入栈,方法退出,出栈。线程私有

本地方法栈

JAVA虚拟机栈,区别是Native方法的栈。线程私有

HotSpot虚拟机不区分上面两个栈
这两个栈可能发生StackOverFlow(方法调用过深,栈帧占用内存超出栈大小)OOM(没有足够内存创建新栈(线程))
虚拟机 通过-Xss参数可以配置每条线程本地方法栈的大小-Xss128k
因此可以通过调小栈大小达到增加最大创建线程数的目的
栈包含许多栈帧,每个帧存储局部变量表,操作数栈,动态链接,返回地址等信息

image.png

JAVA堆

存放对象实例,GC的主要区域,分代(新生代,老年代),线程共享

GC算法:

①标记清除: a.标记要回收的对象 b.回收被标记的对象 (碎片问题,效率问题)
②复制算法(新生代使用): 0. 内存分大小相同的两块,每次只用一块 a.将存活对象移动到另外一块内存 b.清理已使用的内存 (内存少一半)
③标记整理(老年代使用): a.标记要回收的对象 b.存活对象向一端移动,清理端外的内存

堆分代收集
新生代(minor GC): 一个Eden区,两个Survival区from,to。 Eden:Survivals = 8 : 1
老年代(full GC):新生代:老年代 = 1:2.

GC安全点与安全区域
??./.todo

为什么分代?

为什么新生代复制而老年代标记整理?

方法区

存储加载的类信息 ,常量,静态变量
Class 对象???、final、static

线程共享
运行时常量池 Ta在方法区内
Ta 存储运行期间加入的常量String::intern()
以及.class文件中的常量池

直接内存

NIO

对象的创建

new object()
1、类加载、解析、初始化:虚拟机遇到new时先检查此指令的参数是否能在常量池 中找到类的符号引用,并检查符号引用代表的类是否被加载、解析、初始化,若没有则先进行类加载。

2、对象内存分配:虚拟机为新生对象分配内存,对象所需内存大小在类加载完成后便可完全确定。分配内存的任务等同于从堆中分出一块确定大小的内存。
分配方式分为指针碰撞 (空闲内存是整理好的,从空闲的内存割一块)
和空闲列表(内存是乱的,找到足够大的空闲的一块分配)

并发控制:多个对象同时从堆中分配内存因此需要同步
两种解决方案:

3、对象的初始化:对象头和对象实例数据的初始化 <init>

  1. 调用 new操作符
  2. 调用Classjava.lang.reflect.Constructor对象的newInstance()方法
  3. 调用任何现有对象的clone()方法
  4. 通过java.io.ObjectInputStream类的 getObject()方法反序列化

定位对象

句柄访问

image.png

内存移动(GC)的时候,本地变量表中reference不用变,只用改变句柄中的指针
但是多了一次指针定位

直接指针

image.png

相反。少一次

image.png image.png image.png
上一篇 下一篇

猜你喜欢

热点阅读