第二章 JAVA内存区域与内存溢出异常

2.2 运行时数据区域

由所有线程共享的数据区:

  • 方法区 Method Area

https://www.cnblogs.com/duanxz/p/3728737.html

用于存储已被虚拟机加载的类信息、常量、静态变量、及时编译器编译后的代码等数据。

对于JDK中的class,JVM会在启动的时候把这些类加载到方法区中。

  • 堆 Heap

几乎分配了所有对象实例和数组的内存,但是随着JIT 编译器的发展与逃逸技术逐渐成熟,这一说法并没有那么绝对。

垃圾收集器管理的主要区域,“GC堆”

线程隔离的数据区:

  • 虚拟机栈 VM stack

生命周期同线程相同,每个Java方法在执行的时候,在虚拟机栈中新建栈帧,存储局部变量表、动态链接、操作数栈、方法出口。

局部变量表的大小在编译时唯一确定。

爆栈:StackOverFlowError 异常(线程请求深度大于虚拟机所需深度)

无法申请到足够的内存空间:OutOfMemoryError异常

  • 本地方法栈 Native Method Stack

本地方法(Native Method )是指 一个java调用非java代码的接口,他是这样一个java的方法:该方法的实现由非java语言实现,比如C。

本地方法主要用来让java程序和操作系统和java环境外进行交互,可以用本地方法实现一些JVM没有封装的OS的系统调用的接口,使得java程序可以和操作系统的底层和硬件进行交互。

除此,本地方法栈和虚拟机栈的功能一致。

  • 程序计数器 Program Counter Register

当前线程所执行的虚拟机字节码的行号指示器,可以理解为指令指针。

2.3 对象的创建

  • new指令:

当虚拟机遇到new指令时,先看new后面的参数能否再常量池中找到对用的符号引用,但后看它对应的类有没有被加载、解析、初始化。没有的话,先执行类的加载(使用classloader将类从硬盘加载到方法区)。然后虚拟机再为new出来的对象分配内存(堆),这就等同于再堆中新划出来一块内存,这个内存的大小在类加载完之后是唯一确定的。如果堆内存绝对规整,空闲和占用分别在两端,则中间用一个指针指示分界线,新分配内存时,只需要将指针像空闲方向移动应距离,这种分配方式称为“指针碰撞”。如果堆内存不规整,则需要维护一个列表,该列表记录堆内存中哪些空间是可用的,这种分配方式称为“空闲列表”。

  • 指针移动的线程安全问题:

因对象的创建和访问是比较频繁的,移动指针的操作不是线程安全的,解决方案:

  1. 对指针的移动使用同步锁,保证原子性。
  2. 为每个线程在堆中预先分配一块内存(本地线程分配缓冲TLAB),之后该线程需要分配的内存优先从TLAB中分配,当TLAB用完时,为该内存分配新的TLAB,这部操作需要同步锁。
  • 初始化

内存分配完成后,虚拟机将分配到的内存空间都初始化为零值。

2.3.2 对象的内存布局

对象的哈希码: 哈希码并不是完全唯一的,它是一种算法,让同一个类的对象按照自己不同的特征尽量的有不同的哈希码,但不表示不同的对象哈希码完全不同。也有相同的情况,看程序员如何写哈希码的算法。


在Java中,哈希码代表对象的特征。
例如对象 String str1 = “aa”, str1.hashCode= 3104
String str2 = “bb”, str2.hashCode= 3106
String str3 = “aa”, str3.hashCode= 3104
根据HashCode由此可得出str1!=str2,str1==str3
下面给出几个常用的哈希码的算法。
1、Object类的hashCode.返回对象的 [1] 内存地址经过处理后的结构,由于每个对象的内存地址都不一样,所以哈希码也不一样。
2、String类的hashCode.根据String类包含的字符串的内容,根据一种特殊算法返回哈希码,只要字符串所在的堆空间相同,返回的哈希码也相同。
3、Integer类,返回的哈希码就是Integer对象里所包含的那个整数的数值,例如Integer i1=new Integer(100),i1.hashCode的值就是100 。由此可见,2个一样大小的Integer对象,返回的哈希码也一样。

对象在内存中的存储布局可以分为:

对象头Header、实例数据Instance Data 和 对齐补充Padding

2.4 实战:OutOfMemoryError异常

首先设置JVM的最大堆内存,取20m,在IDEA中,点击右上角Edit Configuration设置,找到VM options,输入-Xms20m -Xmx20m表示最大最小堆内存均为20m。

编写Main.java:

import java.util.*;

public class Main {
static class OOMtest{

}

public static void main(String[] args) throws Exception{
List<OOMtest> list = new ArrayList<OOMtest>();

while(true){
list.add(new OOMtest());
}
}
}

Main.java

运行结果:

https://blog.csdn.net/panda_in5/article/details/79841340

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值