点击蓝字
关注dd

作用
JVM在执行JAVA程序时会把它管理的内存区域划分为若干个不同的数据区域,统称为运行时数据区。而对其进行划分主要是便于不同类型数据的管理。
分布
运行时数据区可划分为程序计数器、Java虚拟机栈、本地方法栈、方法区、和堆。其中又可分类为线程私有和线程共享的。
程序计数器
程序计数器拥有较小的内存空间,而且是线程私有的,存储线程当前执行指令的地址。
Java虚拟机栈
Java虚拟机栈是线程私有的,存储局部变量表、操作数栈、动态链接以及方法出口等。
本地方法栈
本地方法栈与虚拟机栈所发挥的作用是非常相似的。
其区别只是虚拟机栈为虚拟机执行Java方法(也就是字节码)服务。而本地方法栈则是为虚拟机使用到的本地(Native)方法服务。
方法区
方法区是线程共享的,存储已被虚拟机加载的类型信息、常量、静态变量、即时编译器编译后的代码缓存等数据。
方法区属于堆的一部分,具体实现由JDK决定 ,在JDK7的实现是永久代, JDK8的实现是元空间。
Java堆
最大的一块内存空间,在虚拟机启动时创建。
Java堆是线程共享的,存储着对象实例、数组。
Java堆划分为新生代、老年代,这两部分内存的比例为1:2。
新生代又可划分为Eden、Servivor0、Servivor1区,比例为8:1:1。
关于对象
对象存储在堆内存中。
创建对象的方式
创建对象的方式有几种:通过new关键字的方式。
通过调用Class的newInstance()方法。
Construstor的newInstance()方法(推荐)。
使用反序列化、使用clone()方法。
使用第三方库Objenesis等。
创建对象的步骤
判断对象是否加载、链接、初始化。
分配内存:规整内存,进行指针碰撞。不规整内存,虚拟机维护空闲列表。
处理并发安全问题:采用cas失败重试策略保证原子性-给每个线程分配一块TLAB空间。
初始化分配到的空间:所有属性设置默认值。
设置对象头。
执行init方法。
对象的内存布局
对象头:运行时元数据(hashCode、GC分代年龄、锁状态标志位、线程持有的锁、偏向线程id、偏向时间戳)、类型指针(指向类元数据instanceKlass,确定该对象所属的类型)、如果是数组,还要记录数组长度。
实例数据:存储程序代码中定义的各种类型的字段,相同宽度的字段总是被分配在一起,父类定义的变量会出现在子类之前。
对齐填充:不是必须的,仅仅起到占位符的作用。
局部变量表
局部变量表存放了编译期可知的各种Java虚拟机基本数据类型(boolean、byte、char、short、int、float、long、double)、对象引用(reference类型)和returnAddress类型(指向了一条字节码指令的地址。
数据类型在局部变量表中的存储空间以局部变量槽(Slot)来表示,其中64位长度的long和double类型的数据会占用两个变量槽,其余的数据类型只占用一个。
异常
StackOverFlowError:Java虚拟机栈、本地方法栈。
OutOfMemoryError:堆、Java虚拟机栈、本地方法栈、方法区。

喜欢本篇内容请给dd点个在看
