原文链接:http://www.cnblogs.com/laoyangHJ/archive/2011/08/17/gc-Stack.html

在JVM中,内存分为两个部分,Stack(栈)和Heap(堆),这里,我们从JVM的内存管理原理的角度来认识Stack和Heap,并通过这些原理认清Java中静态方法和静态属性的问题。

  一般,JVM的内存分为两部分:Stack和Heap。

  Stack(栈)是JVM的内存指令区。Stack管理很简单,push一定长度字节的数据或者指令,Stack指针压栈相应的字节位移;pop一定字节长度数据或者指令,Stack指针弹栈。Stack的速度很快,管理很简单,并且每次操作的数据或者指令字节长度是已知的。所以Java 基本数据类型,Java 指令代码,常量都保存在Stack中。

  Heap(堆)是JVM的内存数据区。Heap 的管理很复杂,每次分配不定长的内存空间,专门用来保存对象的实例。在Heap 中分配一定的内存来保存对象实例,实际上也只是保存对象实例的属性值,属性的类型和对象本身的类型标记等,并不保存对象的方法(方法是指令,保存在 Stack中),在Heap 中分配一定的内存保存对象实例和对象的序列化比较类似。而对象实例在Heap 中分配好以后,需要在Stack中保存一个4字节的Heap 内存地址,用来定位该对象实例在Heap 中的位置,便于找到该对象实例。

  由于Stack的内存管理是顺序分配的,而且定长,不存在内存回收问题;而Heap 则是随机分配内存,不定长度,存在内存分配和回收的问题; 因此在JVM中另有一个GC进程,定期扫描Heap ,它根据Stack中保存的4字节对象地址扫描Heap ,定位Heap 中这些对象,进行一些优化(例如合并空闲内存块什么的),并且假设Heap 中没有扫描到的区域都是空闲的,统统refresh(实际上是把Stack中丢失了对象地址的无用对象清除了),这就是垃圾收集的过程;关于垃圾收集的更 深入讲解请参考51CTO之前的文章《JVM内存模型及垃圾收集策略解析》。


JVM的体系结构

  我们首先要搞清楚的是什么是数据以及什么是指令。然后要搞清楚对象的方法和对象的属性分别保存在哪里。

  1)方法本身是指令的操作码部分,保存在Stack中;

  2)方法内部变量作为指令的操作数部分,跟在指令的操作码之后,保存在Stack中(实际上是简单类型保存在Stack中,对象类型在Stack中保存地址,在Heap 中保存值);上述的指令操作码和指令操作数构成了完整的Java 指令。

  3)对象实例包括其属性值作为数据,保存在数据区Heap 中。

  非静态的对象属性作为对象实例的一部分保存在Heap 中,而对象实例必须通过Stack中保存的地址指针才能访问到。因此能否访问到对象实例以及它的非静态属性值完全取决于能否获得对象实例在Stack中的地址指针。

  非静态方法和静态方法的区别:

  非静态方法有一个和静态方法很重大的不同:非静态方法有一个隐含的传入参数,该参数是JVM给它的,和我们怎么写代码无关,这个隐含的参数就是
对象实例在Stack中的地址指针。因此非静态方法(在Stack中的指令代码)总是可以找到自己的专用数据(在Heap
中的对象属性值)。当然非静态方法也必须获得该隐含参数,因此非静态方法在调用前,必须先new一个对象实例,获得Stack中的地址指针,否则JVM将
无法将隐含参数传给非静态方法。

  静态方法无此隐含参数,因此也不需要new对象,只要class文件被ClassLoader load进入JVM的Stack,该静态方法即可被调用。当然此时静态方法是存取不到Heap 中的对象属性的。

  总结一下该过程:当一个class文件被ClassLoader load进入JVM后,方法指令保存在Stack中,此时Heap
区没有数据。然后程序技术器开始执行指令,如果是静态方法,直接依次执行指令代码,当然此时指令代码是不能访问Heap
数据区的;如果是非静态方法,由于隐含参数没有值,会报错。因此在非静态方法执行前,要先new对象,在Heap
中分配数据,并把Stack中的地址指针交给非静态方法,这样程序技术器依次执行指令,而指令代码此时能够访问到Heap 数据区了。

  静态属性和动态属性:

  前面提到对象实例以及动态属性都是保存在Heap 中的,而Heap
必须通过Stack中的地址指针才能够被指令(类的方法)访问到。因此可以推断出:静态属性是保存在Stack中的,而不同于动态属性保存在Heap
中。正因为都是在Stack中,而Stack中指令和数据都是定长的,因此很容易算出偏移量,也因此不管什么指令(类的方法),都可以访问到类的静态属
性。也正因为静态属性被保存在Stack中,所以具有了全局属性。

  在JVM中,静态属性保存在Stack指令内存区,动态属性保存在Heap数据内存区。

JAVA虚拟机中的堆内存Heap与栈内存Stack的更多相关文章

  1. JVM内存—堆(heap)栈(stack)方法区(method) (转)

    JAVA的JVM的内存可分为3个区:堆(heap).栈(stack)和方法区(method) 堆区:1.存储的全部是对象,每个对象都包含一个与之对应的class的信息.(class的目的是得到操作指令 ...

  2. 《深入理解Java虚拟机》-----第3章 垃圾收集器与内存分配策略

    Java与C++之间有一堵由内存动态分配和垃圾收集技术所围成的“高墙”,墙外面的人想进去,墙里面的人却想出来. 3.1 概述 说起垃圾收集(Garbage Collection,GC),大部分人都把这 ...

  3. Java 虚拟机中的运行时数据区分析

    本文基于 JDK1.8 阐述分析 运行过程 我们都知道 Java 源文件通过编译器编译后,能产生相应的 .Class 文件,也就是字节码文件.而字节码文件通过 Java 虚拟机中的解释器,编译成特定机 ...

  4. 深入理解Java虚拟机--中

    深入理解Java虚拟机--中 第6章 类文件结构 6.2 无关性的基石 无关性的基石:有许多可以运行在各种不同平台上的虚拟机,这些虚拟机都可以载入和执行同一种平台无关的字节码(ByteCode),从而 ...

  5. Java虚拟机详解(二)------运行时内存结构

    首先通过一张图了解 Java程序的执行流程: 我们编写好的Java源代码程序,通过Java编译器javac编译成Java虚拟机识别的class文件(字节码文件),然后由 JVM 中的类加载器加载编译生 ...

  6. (转)java内存分配分析/栈内存、堆内存

    转自(http://blog.csdn.net/qh_java/article/details/9084091) java内存分配分析/栈内存.堆内存 java内存分配分析 本文将由浅入深详细介绍Ja ...

  7. 理解Java虚拟机中的栈、堆、堆栈

    JAVA的JVM的内存可分为3个区:堆(heap).栈(stack)和方法区(method) 栈区: 每个线程包含一个栈区,栈中只保存方法中(不包括对象的成员变量)的基础数据类型和自定义对象的引用(不 ...

  8. Java虚拟机中的内存分配

    java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同的数据区域.这些区域都有各自的用途以及创建和销毁的时间. 栈:存放的是局部变量,包括:1.用来保存基本数据类型的值:2.保存类 ...

  9. Java虚拟机中Java内存区域

      Java虚拟机所管理的内存将会包括以下几个运行时数据区域. 程序计数器 可以看作是当前线程所执行的字节码的行号指示器. 每一个线程都需要有一个独立的程序计数器. 如果线程正在执行的是一个Java方 ...

随机推荐

  1. Day1 Markdown学习!

    Markdown学习 标题 一级标题:# (空格)+内容 二级标题:##(空格)+内容 同理可支持到六级标题 字体 Hello,World! 两边两个** 加粗 Hello,World! 两边一个* ...

  2. 两台Linux系统之间传输文件的几种方法

    两台Linux系统之间传输文件的几种方法:参考https://www.cnblogs.com/bignode/articles/9241333.html

  3. Python+Requests+异步线程池爬取视频到本地

    1.本次项目为获取梨视频中的视频,再使用异步线程池下载视频到本地 2.获取视频时,其地址中的Url是会动态变化,不播放时src值为图片的地址,播放时src值为mp4格式 3.查看视频链接是否存在aja ...

  4. Tomcat修改最大连接数及查看最大连接数

    一.背景 公司进行安全整改, 技术要求:会话限制:应能够对应用系统的最大并发会话连接数进行限制: 提供凭证:提供对系统最大并发会话连接数进行限制的截图,需要将所有被检查系统中间件配置截图,如果不限制最 ...

  5. Cesium加载地形数据只显示半个地球

    Cesium第0级地形包括两个瓦片:0/0/0.terrain,0/1/0.terrain,分别为左半球和右半球(具体参考:https://blog.csdn.net/u013929284/artic ...

  6. C++第四十九篇 -- 将一个项目Copy到另一台电脑

    最近写项目,由于设备原因,需要将一台电脑的项目拷贝到另一台电脑上,在另一个电脑上继续编写.由于配置属性原因,最终还是在另一台电脑上创建了新项目,只是把这些cpp文件都复制过去了,然后重新部署属性. 背 ...

  7. Django模板中变量的运算

    在django中的模板下我们知道变量使用{{xxx}}来呈现,可是当出现两个变量进行运算怎么处理那? #加法: {{value|add:value2}} #返回的结果是value+value2的值,假 ...

  8. 谷粒商城--分布式高级篇P102~P128

    谷粒商城--分布式高级篇P102~P128 由于学习的时间也比较少,只有周六周末才有时间出来学习总结,所以一篇一篇慢慢更新吧,本次总结内容为Elasticsearch(相关内容:kibana,es,n ...

  9. springboot整合mybatis源码分析

    springboot整合mybatis源码分析 本文主要讲述mybatis在springboot中是如何被加载执行的,由于涉及的内容会比较多,所以这次只会对调用关系及关键代码点进行讲解,为了避免文章太 ...

  10. tp phpexcel 导入后台访问方法

    public function addall(){ $Water = M('Waterrate'); $config = array( 'maxSize' => 0, 'rootPath' =& ...