JVM 之 java 内存区域与内存溢出异常

一。走近 Java
1.java 优点:
   1.1 摆脱硬件平台得束缚,实现了“一次编写,到处运行”
   1.2 提供了一个相对安全的内存管理和访问机制,避免了绝大部分得内存泄露和指针越界问题。
   1.3 实现了热点代码检测和运行时编译及优化,这使得Java应用能随着运行时间得增加而获得更高得性能。
2. java虚拟机,Java API类库, Java程序设计语言这三部分统称 JDK,JDK是用于支持Java 程序开发得最小环境。
    Java API 类库中得 JavaSE API子集,和Java 虚拟机这两部分 通常为 JRE.  JRE是 支持Java程序运行的标准环境
.    
二 Java内存区域与内存溢出异常
 1.运行时数据区域
   1.1 程序计数器(线程私有):是一块较小得内存空间,它可以看作是 当前线程 所执行得 字节码 得 行号指示器。
                             字节码解释器工作时就是通过改变这个计数器的值来选 取下一条 需要执行的字节码指令,
                            分支,循环,跳转,异常处理,线程恢复等基础功能都需要依赖这个计数器来完成。    
  1.2 Java虚拟机栈(线程私有):它的生命周期与线程相同。描述的是Java 方法执行的内存模型,每个方法在执行的
                           同时都会创建一个栈帧,用于存储局部变量表,操作数栈,动态链接,方法出口等信息,每一个方法
                           从调用直至执行完成的过程,就对应着一个栈帧,就对应着一个栈帧在虚拟机栈中入栈到出栈的过程。
                          局部变量表部分存放了 编译器可知的各种基本类型,对象的引用。 
  1.3 本地方法栈:类似于   Java虚拟机栈
  1.4 Java堆:      堆是Java虚拟机所管理的内存中最大的一块。java堆是被所有线程共享的一块内存区域,在虚拟机启动时
                          创建。此内存区域的唯一目的就是存放对象实例,几乎所有的对象实例都在这里分配内存。
                            java 堆是垃圾收集器管理的主要区域。
  1.5 方法区:     方法区与java 堆一样,是各个线程共享的内存区域,它用于存储已经被虚拟机 加载的类信息(类名,访问修饰,常量池,                               字段描述,方法描述等),常量,静态变量,
                         即时编译器编译后的代码等数据。
  1.6运行时常量池:方法区的一部分, Class 文件中除了有类的版本,字段,方法,接口等描述信息外还一项信息是 常量池,用于
                            存放编译期生成的各种字段量和符号引用,这部分内容将在类加载后进入方法区的运行时 常量池中存放。
  1.7 直接内存:

2. HotSpot 虚拟机对象探秘
   2.1:对象的创建:虚拟机遇到一条new 指令时,首先将去 检查这个指令的参数是否能在 常量池中 定位到一个类的符号 引用,并检查这个
                              符号引用代表的类是否已被加载,解析和初始化过。如果没有,那必须先执行相应的类加载过程。在类加载检查通过后,
                              接下来虚拟机将为新生对象分配内存。
                             内存分配完成后,虚拟机需要将分配到的内存空间都初始化为 0值,这一步操作保证了对象的实例字段在JAVA 代码中可以
                             不赋初始值就直接使用,程序能访问到这些字段的数据类型 所对应的零值。
                             init 初始化
 2.2 :对象的内存布局:对象头 实例数据 对齐填充
       2.2.1:对象头:包括两部分信息:1:存储对象自身的运行时数据,如哈西吗,Gc分代年龄,锁 状态标志,线程持有的锁,偏向线程ID,
                              偏向时间戳等。2:类型指针,即对象指向它的 类元数据的指针,虚拟机通过这个指针确定这个对象是哪个类的实例。
      2.2.2: 实例数据:是对象真正存储的有效信息,也是在程序代码中所定义的各种类型的字段内容。
      2.3: 对齐填充:不是必然存在的。仅仅起着占位符的作用。对象的大小必须是8字节的整数倍,当对象实例数据部分没有对其时,就需要                                   对齐填充。
2.3 对象的访问定位:建立对象是为了使用对象,我们的JAva程序需要通过栈上的reference 数据操作堆上的具体对象。目前主流的方式有
                                使用句柄和直接指针两种。 
                              句柄: 如果使用句柄访问的话,那么Java 堆中将会划分出一块内存来作为句柄池,reference 中存储的就是 对象的句柄
                                       地址,而句柄中包含了对象实例数据与类型数据各自的具体地址信息。
                             指针:如果使用指针访问,那么Java 堆对象 的布局中就必须考虑如何放置访问类型数据的相关信息。而reference 中存储                                       的直接就是对象地址。
                                  使用句柄:reference中 存储的是稳定的句柄地址,在对象被移动时只会 改变句柄中的实例数据指针,而reference 
                                                  本身不需要修改。
                                 使用指针:速度快。节省了指针定位的时间开销。
2.4 内存溢出异常
                      死循环创建对象
2.5 方法区和运行时常量池溢出。(String.intern()是一个Native 方法,它的作用是:如果字符串常量池中已经包含了一个等于此String对象的                                                  字符串,则返回代表池中这个字符串的String对象,否则,将此String对象包含的字符串添加到常量池中,
                                                    并返回此String对象的引用。)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值