JVM的堆分配
为了展示虚拟机如何使用方法区中的信息,下面来举例说明:
class Lava {
private int speed = 5;
void flow(){
}
}
public class Volcano {
public static void main(String[] args){
Lava lava = new Lava();
lava.flow();
}
}
不同的虚拟机实现可能会用完全不同的方法来操作,下面描述的只是其中一种可能——但并不是仅有的一种。
要运行Volcano程序,首先得以某种“依赖于实现的”方式告诉虚拟机“Volcano”这个名字。之后,虚拟机将找到并读入相应的class文件“Volcano.class”,然后它会从导入的class文件里的二进制数据中提取类型信息并放到方法区中。通过执行保存在方法区中的字节码,虚拟机开始执行main()方法,在执行时,它会一直持有指向当前类(Volcano类)的常量池(方法区中的一个数据结构)的指针。
注意:虚拟机开始执行Volcano类中main()方法的字节码的时候,尽管Lava类还没被装载,但是和大多数(也许所有)虚拟机实现一样,它不会等到把程序中用到的所有类都装载后才开始运行。恰好相反,它只会需要时才装载相应的类。
main()的第一条指令告知虚拟机为列在常量池第一项的类分配足够的内存。所以虚拟机使用指向Volcano常量池的指针找到第一项,发现它是一个对Lava类的符号引用,然后它就检查方法区,看Lava类是否已经被加载了。
这个符号引用仅仅是一个给出了类Lava的全限定名“Lava”的字符串。为了能让虚拟机尽可能快地从一个名称找到类,虚拟机的设计者应当选择最佳的数据结构和算法。
当虚拟机发现还没有装载过名为“Lava”的类时,它就开始查找并装载文件“Lava.class”,并把从读入的二进制数据中提取的类型信息放在方法区中。
紧接着,虚拟机以一个直接指向方法区Lava类数据的指针来替换常量池第一项(就是那个字符串“Lava”),以后就可以用这个指针来快速地访问Lava类了。这个替换过程称为常量池解析,即把常量池中的符号引用替换为直接引用。
终于,虚拟机准备为一个新的Lava对象分配内存。此时它又需要方法区中的信息。还记得刚刚放到Volcano类常量池第一项的指针吗?现在虚拟机用它来访问Lava类型信息,找出其中记录的这样一条信息:一个Lava对象需要分配多少堆空间。
JAVA虚拟机总能够通过存储与方法区的类型信息来确定一个对象需要多少内存,当JAVA虚拟机确定了一个Lava对象的大小后,它就在堆上分配这么大的空间,并把这个对象实例的变量speed初始化为默认初始值0。
当把新生成的Lava对象的引用压到栈中,main()方法的第一条指令也完成了。接下来的指令通过这个引用调用Java代码(该代码把speed变量初始化为正确初始值5)。另一条指令将用这个引用调用Lava对象引用的flow()方法。
堆
Java程序在运行时创建的所有类实例或数组都放在同一个堆中。而一个JAVA虚拟机实例中只存在一个堆空间,因此所有线程都将共享这个堆。又由于一个Java程序独占一个JAVA虚拟机实例,因而每个Java程序都有它自己的堆空间——它们不会彼此干扰。但是同一个Java程序的多个线程却共享着同一个堆空间,在这种情况下,就得考虑多线程访问对象(堆数据)的同步问题了。
JAVA虚拟机有一条在堆中分配新对象的指令,却没有释放内存的指令,正如你无法用Java代码去明确释放一个对象一样。虚拟机自己负责决定如何以及何时释放不再被运行的程序引用的对象所占据的内存。通常,虚拟机把这个任务交给垃圾收集器。
对象分配规则
对象优先分配在Eden区,如果Eden区没有足够的空间时,虚拟机执行一次Minor GC。
大对象直接进入老年代(大对象是指需要大量连续内存空间的对象)。这样做的目的是避免在Eden区和两个Survivor区之间发生大量的内存拷贝(新生代采用复制算法收集内存)。
长期存活的对象进入老年代。虚拟机为每个对象定义了一个年龄计数器,如果对象经过了1次Minor GC那么对象会进入Survivor区,之后每经过一次Minor GC那么对象的年龄加1,知道达到阀值对象进入老年区。
动态判断对象的年龄。如果Survivor区中相同年龄的所有对象大小的总和大于Survivor空间的一半,年龄大于或等于该年龄的对象可以直接进入老年代。
空间分配担保。每次进行Minor GC时,JVM会计算Survivor区移至老年区的对象的平均大小,如果这个值大于老年区的剩余值大小则进行一次Full GC,如果小于检查HandlePromotionFailure设置,如果true则只进行Monitor GC,如果false则进行Full GC。
数组的内部表示
在Java中,数组是真正的对象。和其他对象一样,数组总是存储在堆中。同样,数组也拥有一个与它们的类相关联的Class实例,所有具有相同维度和类型的数组都是同一个类的实例,而不管数组的长度(多维数组每一维的长度)是多少。例如一个包含3个int整数的数组和一个包含300个整数的数组拥有同一个类。数组的长度只与实例数据有关。
数组类的名称由两部分组成:每一维用一个方括号“[”表示,用字符或字符串表示元素类型。比如,元素类型为int整数的、一维数组的类名为“[I”,元素类型为byte的三维数组为“[[[B”,元素类型为Object的二维数组为“[[Ljava/lang/Object”。
多维数组被表示为数组的数组。比如,int类型的二维数组,将表示为一个一维数组,其中的每一个元素是一个一维int数组的引用,如下图:

在堆中的每个数组对象还必须保存的数据时数组的长度、数组数据,以及某些指向数组的类数据的引用。虚拟机必须能够通过一个数组对象的引用得到此数组的长度,通过索引访问其元素(期间要检查数组边界是否越界),调用所有数组的直接超类Object声明的方法等等。
JVM的堆分配的更多相关文章
- JVM的堆(heap)、栈(stack)和方法区(method)
JVM主要由类加载器子系统.运行时数据区(内存空间).执行引擎以及与本地方法接口等组成.其中运行时数据区又由方法区Method Area.堆Heap.Java stack.PC寄存器.本地方法栈组成. ...
- [转]JVM内存堆布局图解分析
JAVA能够实现跨平台的一个根本原因,是定义了class文件的格式标准,凡是实现该标准的JVM都能够加载并解释该class文件,据此也可以知道,为啥Java语言的执行速度比C/C++语言执行的速度要慢 ...
- JVM是如何分配和回收内存?有实例!
上一篇博客我简单介绍了下如何手动计算一个Java对象到底占用多少内存?今天就想聊下这个内存JVM到底是是如何分配和回收的. Java整体来说还是一个GC比较友好的语言,无论是分代的垃圾收集,还是基于G ...
- JVM内存堆布局图解分析
JAVA能够实现跨平台的一个根本原因,是定义了class文件的格式标准,凡是实现该标准的JVM都能够加载并解释该class文件,据此也可以知道,为啥Java语言的执行速度比C/C++语言执行的速度要慢 ...
- 浅谈JVM与内存分配
一.程序内存分配 初始内存分配 当一个程序准备运行时,它首先向java虚拟机要内存,但是java虚拟机本身没有权限,它只能向操作系统申请内存,此时java虚拟机会拥有一个初始内存, 此处额外说明一下e ...
- JVM初探- 内存分配、GC原理与垃圾收集器
JVM初探- 内存分配.GC原理与垃圾收集器 标签 : JVM JVM内存的分配与回收大致可分为如下4个步骤: 何时分配 -> 怎样分配 -> 何时回收 -> 怎样回收. 除了在概念 ...
- JVM总结(二):JVM的内存分配策略
这节我们总结一下JVM中的内存分配策略.目录如下: 内存分配策略 对象优先在新生代Eden分配 大对象直接进入老年代 长期存活的对象将进入老年代 动态对象年龄判定 空间分配担保 内存分配策略 Java ...
- Java 中的 JVM、堆和栈 -- 初步了解
JVM -- Java Virtual Machine(Java虚拟机) —— 因为要说堆和栈,所以我们必须要先简单的说一下JVM.(JVM详细请找度娘啦~) 首先,我们都知道 java 一直宣传的口 ...
- jvm对象内存分配
一.jvm简单结构图 1.jvm内存对象分配整体流程: 1.类加载子系统和方法区 类加载子系统负责从文件系统或者网络中加载Class信息,加载的类信息存放于一块称为方法区的内存空间.除了类的信息外, ...
随机推荐
- 15个超实用的php正则表达式
在这篇文章里,我已经编写了15个超有用的正则表达式,WEB开发人员都应该将它收藏到自己的工具包. 验证域名 检验一个字符串是否是个有效域名. $url = "http://komunitas ...
- IE7 -- 鼠标移入显示下拉框 不显示的问题 / 以及宽度问题
这个问题,真的是打击到我了,我一度不相信自己无法解决这个问题.但是我就是真的没有解决. 那么问题解决方案是: 第一 祖先级别有一个相对定位,父级再有一个定位,那么绝对定位显示出来的元素就会不显示. 第 ...
- 繁华模拟赛 David与阶乘
#include<cstdio> #include<iostream> #include<algorithm> #include<cstring> #i ...
- java笔记--关于线程死锁
关于线程死锁 什么是死锁: 在编写多线程的时候,必须要注意资源的使用问题,如果两个或多个线程分别拥有不同的资源, 而同时又需要对方释放资源才能继续运行时,就会发生死锁. 简单来说:死锁就是当一个或多个 ...
- nginx-upload-module模块实现文件断点续传
导读 每当我们想简单的实现文件上传功能,而又不使用其他的语言(比如PHP.Java),或者想实现文件的断点续传.这个时候Nginx的一个模块nginx-upload-module就能满足我们的需求. ...
- 代码风格与树形DP
Streaming很惨,不过因为比赛之间没有提交过就没掉(或掉了)rating.第二题是一个树形DP,但是我都在想第一题了,简直作死. 看着神犇的代码我也是醉了...各种宏,真是好好写会死系列. 看到 ...
- scrapy和selenium结合抓取动态网页
1.安装python (我用的是2.7版本的) 2.安装scrapy: 详情请参考 http://blog.csdn.net/wukaibo1986/article/details/8167590 ...
- Quartz作业调度框架
Quartz 是一个开源的作业调度框架,它完全由 Java 写成,并设计用于 J2SE 和 J2EE 应用中.它提供了巨大的灵活性而不牺牲简单性.你能够用它来为执行一个作业而创建简单的或复杂的调度.本 ...
- 1.1 让CPU占用率曲线听你指挥[cpu manager]
[本文链接] http://www.cnblogs.com/hellogiser/p/cpu-manager.html [题目] 写一个程序,让用户来决定Windows任务管理器(Task Manag ...
- Java用Scanner类获取用户输入
用Java编写程序时,有些数据需要用户输入,这个时候需要调用java提供的Scanner类,这个类在包java.util下,比如求一个矩形的面积,简单的看一下用法: import java.util. ...