对于Java程序员,在虚拟机自动内存管理机制的帮助下,不需要再为每一个操作写配对的释放资源操作,不容易出现内存泄露和内存溢出问题。加深对Java虚拟机的理解,有助于在发现问题时精准定位问题,排查错误因素,写出更健壮的代码。
一、虚拟机内存
Java虚拟机在执行Java程序时,会把它所管理的内存划分成若干个不同的数据区域。这些区域都有各自的用途,以及创建和销毁的时间。从粗略的角度来说,可以分为堆和栈。堆为线程公有,栈为线程私有。
1.1 程序计数器
程序计数器是一块较小的内存空间,它可以看做是当前线程所执行的字节码的行号指示器。字节码解释器工作时,就是通过改变这个计数器的值来选取下一条需要执行的字节码指令。
为了线程切换后能恢复到正确的执行位置,每个线程都需要有一个独立的程序计数器。各条线程之间的计数器互不影响、独立存储,称这类内存区域为“线程私有”的内存。
1.2 Java虚拟机栈、本地方法栈
Java虚拟机栈(Java Virtual Machine Stacks)也是线程私有的,它的生命周期与线程相同。虚拟机栈描述的是Java方法执行的内存模型:每个方法在执行的同时会创建一个栈帧(Stack Frame),用于存储局部变量表、操作数栈、动态链接、方法出口等信息,每一个方法从调用直至执行完成的过程,就对应着一个栈帧在虚拟机栈中入栈到出栈的过程。
1.3 堆、方法区
对于大多数应用来说,Java堆(Java Heap)是Java虚拟机所管理的内存中最大的一块。Java堆是被所有线程共享的一块内存区域,在虚拟机启动时创建。此内存区域的唯一目的就是存放对象实例,几乎所有的对象实例都在这里分配内存:所有的对象实例以及数组都要在堆上分配。
方法区(别名非堆:Non-Heap)是各个线程共享的内存区域,它用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。
1.4 运行时常量池
运行时常量池(Runtime Constant Pool)是方法区的一部分。——用于存放类加载后的编译信息
1.5 直接内存
2、对象
2.1 对象的创建
①运行时常量池-检查类是否已被加载
②为新生对象分配内存
指针碰撞 Bump the Pointer :假设Java堆中的内存是绝对规整的,内存区分为可用和已用两部分,中间用指针分隔,作为分界点的指示器。分配内存就是将指针向空闲区域移动与对象大小相等的距离。
空闲列表 Free List:Java堆中的内存并不规整,虚拟机维护一个列表,记录哪些内存块是可用的,在分配的时候从列表上找到一个足够大的空间划分给对象实例,并更新列表上的记录。
CAS/失败重试 Compare And Swap:保证分配内存的并发安全
TLAB:本地线程分配缓冲(Thread Local Allocation Buffer):每个线程在Java堆中预先分配一小块内存,哪个线程要分配内存,就先在TLAB上分配,只有当TLAB用完并分配新的TLAB时,才需要同步锁定
③对对象进行必要的设置
将对象信息存储在对象的对象头(Object Head)之中。
2.2 对象的内存布局
对象在内存中存储的布局可以分为3块区域:对象头(Header)、实例数据(Instance Data)、对齐填充(Padding)
①对象头:
Mark Word:存储对象自身的运行时数据,如哈希码(HashCode)、GC分代年龄、锁状态标志、线程持有的锁、偏向线程ID、偏向时间戳等。
类型指针:对象指向它的类元数据的指针,虚拟机通过这个指针来确定这个对象是哪个类的实例,若对象为一个Java数组,则对象头中还必须有一块用于记录数组长度的数据。
②实例数据
③补齐
虚拟机大小必须是8字节的整数倍,不规整的
3、运行测试
1、使用IDEA,设置虚拟机参数: -Xss参数,减小栈内存容量。
测试程序:
public class JavaVMStackSOF {
private int stackLength = 1;
private void stackLeak(){
stackLength ++;
stackLeak();
}
public static void main(String[] args) {
JavaVMStackSOF oom = new JavaVMStackSOF();
try{
oom.stackLeak();
}catch (Throwable e){
System.out.println("stack length:" + oom.stackLength);
throw e;
}
}
}
输出结果:
抛出StackOverflowError异常,异常时输出的堆栈深度相应缩小。
二、垃圾回收策略
1、引用
判断引用是否存在,用于判断对象是否存活。
在JDK1.2之后,Java对对象的引用概念进行扩充, 将引用分为强引用(Strong Reference)、软引用(Soft Reference)、弱引用(Weak Reference)、虚引用(Phantom
Reference)
强引用就是指在程序代码之中普遍存在的、类似于“Object obj = new Object()”这类的引用。只要强引用还存在,垃圾回收器就永远不会回收被引用的对象。
2、垃圾回收算法
①标记-清除算法
最基础的收集算法是“标记-清除”算法:分为“标记”和“清除”两个阶段:首先标记出所有需要回收的对象,在标记完成后统一回收所有被标记的对象。
主要不足:一是效率问题,标记和清除两个过程的效率都不高,二是空间问题,标记清除之后会产生大量不连续的内存碎片,空间碎片太多可能会导致在程序运行过程中,需要分配较大对象时,无法找到足够的连续内存而不得不提前触发另一次垃圾回收动作。
②复制算法
将可用内存划分为两部分,当一部分用完时,将这部分中所有还存活的对象复制到另一部分中,再将已使用过的内存空间一次清理掉。
③标记-整理算法
与标记-清除算法类似,但标记后的后续步骤不是直接对可回收对象进行清理,而是让所有存活的对象都向一端移动。
④分代收集算法
当前商业虚拟机的垃圾回收都采用“分代收集”算法。这种算法并没有什么新的思想,只是根据对象存活周期的不同,将内存划分为新生代、老年代。根据不同年代的特点,采用不同的回收算法。
3、垃圾回收器
①Serial收集器:
②G1收集器
对象优先在Eden分配:
大多数情况下,对象在新生代Eden区中分配,当Eden区没有足够空间进行分配时,虚拟机将发起一次Minor GC。
大对象直接进入老年代:所谓大对象是指需要大量连续内存空间的Java对象,最典型的的大对象就是很长的字符串以及数组。
- Java内存 模型理解
概述 在正式讲Java内存模型之前,我们先了解一些物理计算机并发问题,然后一点点的引出Java内存模型的由来. 多任务处理在现在计算机操作系统中几乎是一项必备的功能.这不单是因为计算机计算能力强大,更 ...
- 从 CPU 讲起,深入理解 Java 内存模型!
Java 内存模型,许多人会错误地理解成 JVM 的内存模型.但实际上,这两者是完全不同的东西.Java 内存模型定义了 Java 语言如何与内存进行交互,具体地说是 Java 语言运行时的变量,如何 ...
- Java 内存区域和GC机制
目录 Java垃圾回收概况 Java内存区域 Java对象的访问方式 Java内存分配机制 Java GC机制 垃圾收集器 Java垃圾回收概况 Java GC(Garbage Collection, ...
- Java系列笔记(3) - Java 内存区域和GC机制
目录 Java垃圾回收概况 Java内存区域 Java对象的访问方式 Java内存分配机制 Java GC机制 垃圾收集器 Java垃圾回收概况 Java GC(Garbage Collection, ...
- 【转载】Java系列笔记(3) - Java 内存区域和GC机制
Java系列笔记(3) - Java 内存区域和GC机制 转载:原文地址http://www.cnblogs.com/zhguang/p/3257367.html 目录 Java垃圾回收概况 Java ...
- Java内存分配以及GC
转自http://www.cnblogs.com/hnrainll/archive/2013/11/06/3410042.html 写的太棒了,简单易懂 Java垃圾回收概况 Java GC(Gar ...
- Java 内存回收机制——GC机制
一.Java GC 概念说明 Java GC(Garbage Collection,垃圾收集,垃圾回收)机制,是Java与C++/C的主要区别之一,作为Java开发者,一般不需要专门编写内存回收和垃圾 ...
- 转载:Java 内存区域和GC机制
原文链接:http://www.cnblogs.com/hnrainll/archive/2013/11/06/3410042.html 目录 Java垃圾回收概况 Java内存区域 Java对象的访 ...
- Java内存区域划分和GC机制
Java 内存区域和GC机制 目录 Java垃圾回收概况 Java内存区域 Java对象的访问方式 Java内存分配机制 Java GC机制 垃圾收集器 Java垃圾回收概况 Java GC(Ga ...
随机推荐
- 徐州赛区网络预赛 D Easy Math
比赛快结束的适合看了一下D题,发现跟前几天刚刚做过的HDU 5728 PowMod几乎一模一样,当时特兴奋,结果一直到比赛结束都一直WA.回来仔细一琢磨才发现,PowMod这道题保证了n不含平方因子, ...
- BeanDefinition源码解析
我们知道BeanDefintion定义了Bean在IoC容器内的基本数据结构.在学习IoC之前先了解BeanDefition对我们理解IoC容器是有帮助的. 首先BeanDefinition是一个接口 ...
- spring boot 集成mybatis使用logback打印并保存日志信息
spring boot 打印执行的sql语句 最近在学习spring boot 整合了Mybatis和druid之后总感觉少点什么东西,看了下在别的项目上用的框架,发现自己整合的东西不打印sql语句, ...
- 疯子的算法总结(九) 图论中的矩阵应用 Part 2 矩阵树 基尔霍夫矩阵定理 生成树计数 Matrix-Tree
定理: 1.设G为无向图,设矩阵D为图G的度矩阵,设C为图G的邻接矩阵. 2.对于矩阵D,D[i][j]当 i!=j 时,是一条边,对于一条边而言无度可言为0,当i==j时表示一点,代表点i的度. 即 ...
- Codeforce 270D Greenhouse Effect
Emuskald is an avid horticulturist and owns the world's longest greenhouse - it is effectively infin ...
- Android 自定义View—清爽小巧灵活的多节点进度条
前言 最近项目有一个节点进度条的小需求,完成后,想分享出来希望可以帮到有需要的同学. 真机效果图 自定义View完整代码 开箱即用~,注释已经炒鸡详细了 /** * @description: 节点进 ...
- 工具类CountDownLatch的应用---百米赛跑案例
package com.aj.thread; import java.util.concurrent.CountDownLatch; import java.util.concurrent.Execu ...
- Spring官网阅读(四)BeanDefinition(上)
前面几篇文章已经学习了官网中的1.2,1.3,1.4三小结,主要是容器,Bean的实例化及Bean之间的依赖关系等.这篇文章,我们继续官网的学习,主要是BeanDefinition的相关知识,这是Sp ...
- 记录:通过ffmpeg rtsp转 http m3u8
环境 Windows 10 大华rtsp直播 转 http请求m3u8 ffmpeg -rtsp_transport tcp -i "rtsp://账号:密码@IP:端口/cam/realm ...
- 【译】Using .NET for Apache Spark to Analyze Log Data
.NET for Spark可用于处理成批数据.实时流.机器学习和ad-hoc查询.在这篇博客文章中,我们将探讨如何使用.NET for Spark执行一个非常流行的大数据任务,即日志分析. 1 什么 ...