A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 于清云 中级黑马   /  2012-4-25 09:00  /  3711 人查看  /  5 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

在毕老师java基础视频中讲到类变量跟实例区别这块,说到类变量随着类的加载存放于方法区中
大虾们,这个方法区到底是个啥东东?跟栈内存 堆内存 有什么区别?

5 个回复

倒序浏览
注意学习,毕老师讲的内存一课就介绍了了JVM内存分Heap(堆)和Stack(栈)两类内存空间。栈空间是用于线程的方法调用的。
通常所说的java内存管理主要指的是Heap空间的分配以及所有java对象自动管理(分配和垃圾回收)
Heap空间主要包括方法区(MethodCode)和数据区,方法区用于存放jvm系统数据和java class的原始数据。通常说的Java Heap区指的是数据区,所有java对象分配在这个空间里。
在一个jvm实例的内部,类型信息被存储在一个称为方法区的内存
逻辑区中。类型信息是由类加载器在类加载时从类文件中提取出来
的。类(静态)变量也存储在方法区中。
希望能帮助你

回复 使用道具 举报
照虚拟机规范所述Java虚拟机栈为执行java方法(字节码)服务,而本地方法栈则是为执行Native方法服务,但这个在不同JVM内有不同的内部实现,比如在HotSpot JVM中Java虚拟机栈和本地方法栈被实现为同一个栈区!
HotSpot JVM中静态字段(包括变量和常量)被分配在方法区(又称永久代)中类型数据结构的末尾!


  2 堆和栈的比较

  上面的定义从编译原理的教材中总结而来,除静态存储分配之外,都显得很呆板和难以理解,下面撇开静态存储分配,集中比较堆和栈:

  从堆和栈的功能和作用来通俗的比较,堆主要用来存放对象的,栈主要是用来执行程序的.而这种不同又主要是由于堆和栈的特点决定的:

  在编程中,例如C/C++中,所有的方法调用都是通过栈来进行的,所有的局部变量,形式参数都是从栈中分配内存空间的。实际上也不是什么分配,只是从栈顶向上用就行,就好像工厂中的传送带(conveyor belt)一样,Stack Pointer会自动指引你到放东西的位置,你所要做的只是把东西放下来就行.退出函数的时候,修改栈指针就可以把栈中的内容销毁.这样的模式速度最快, 当然要用来运行程序了.需要注意的是,在分配的时候,比如为一个即将要调用的程序模块分配数据区时,应事先知道这个数据区的大小,也就说是虽然分配是在程序运行时进行的,但是分配的大小多少是确定的,不变的,而这个"大小多少"是在编译时确定的,不是在运行时.

  堆是应用程序在运行的时候请求操作系统分配给自己内存,由于从操作系统管理的内存分配,所以在分配和销毁时都要占用时间,因此用堆的效率非常低.但是堆的优点在于,编译器不必知道要从堆里分配多少存储空间,也不必知道存储的数据要在堆里停留多长的时间,因此,用堆保存数据时会得到更大的灵活性。事实上,面向对象的多态性,堆内存分配是必不可少的,因为多态变量所需的存储空间只有在运行时创建了对象之后才能确定.在C++中,要求创建一个对象时,只需用 new命令编制相关的代码即可。执行这些代码时,会在堆里自动进行数据的保存.当然,为达到这种灵活性,必然会付出一定的代价:在堆里分配存储空间时会花掉更长

回复 使用道具 举报
  在JVM实例中,对装载的类型信息是存储在一个逻辑方法内存区中,当Java虚拟机加载了一个类型的时候,它会跟着这个Class的类型去路径里面查找对应的Class文件,类加载器读取类文件(线性二进制数据),然后将该文件传递给Java虚拟机,JVM从二进制数据中提取信息并且将这些信息存储在方法区,而类中声明(静态)变量就是来自于方法区中存储的信息。
    方法区的大小在分配过程中是不固定的,随着Java应用程序的运行,JVM可以调整其大小,需要注意一点,方法区的内存不需要是连续的,因为方法区内存可以分配在内存堆中,即使是虚拟机JVM实例对象自己所在的内存堆也是可行的,而在实现过程是允许程序员自身来指定方法区的初始化大小的。
    Java本身的自动内存管理,方法区也会被垃圾回收的,Java程序可以通过类扩展动态加载器对象,类可以成为“未引用”向垃圾回收器进行申请,如果一个类是“未引用”的,则该类就可能被卸载。
堆区: Heap
1.存储的全部是对象,每个对象都包含一个与之对应的class的信息的引用。(class的目的是得到操作指令) 。
2.jvm的堆区(heap)被所有线程共享,堆中不存放基本类型和对象引用,只存放对象本身 。
栈区: Stack
1.每个线程包含一个栈区,栈中只保存基础数据类型的对象和自定义对象的引用(不是对象),对象都存放在堆区中 。
2.每个栈中的数据(原始类型和对象引用)都是私有的,其他栈不能访问。
3.栈分为3个部分:基本类型变量区、执行环境上下文、操作指令区(存放操作指令)。
方法区:
1.又叫静态区,跟堆一样,被所有的线程共享。方法区包含所有的Class(类型定义信息)和static变量。
2.方法区中包含的都是在整个程序中永远唯一的元素,如class,static变量。

回复 使用道具 举报
Java内存共划分5片内存区:
1,堆内存 :存储对象。垃圾回收
2,栈内存 :局部变量数据。所属区域结束释放。
3,方法区 :代码表,静态区,常量池等,可以成为数据共享区。因为生命周期长。
4,本地方法区 :和系统相关,jvm对系统底层进行调用,比如调用C的代码。
5,寄存器 : 和处理器相关。

你可以看看我之前发的帖子,问老师的。
对于毕老师说的内存划分,表示很郁闷。求解释
http://bbs.itheima.com/forum.php ... 3&fromuid=20350
回复 使用道具 举报
用代码来分析,内存中:堆,栈,方法区分布


public   class AppMain                //运行时, jvm 把appmain的信息都放入方法区
{
public   static   void main(String[] args) //main 方法本身放入方法区。
{
Sample test1 = new Sample( " 测试1 " );   //test1是引用,所以放到栈区里, Sample是自定义对象应该放到堆里面
Sample test2 = new Sample( " 测试2 " );

test1.printName();
test2.printName();
}
} Sample.java

public   class Sample        //运行时, jvm 把appmain的信息都放入方法区
{
/** 范例名称 */
private name;      //new Sample实例后, name 引用放入栈区里, name 对象放入堆里

/** 构造方法 */
public Sample(String name)
{
this .name = name;
}

/** 输出 */
public   void printName()   //printName方法本身放入 方法区里。
{
System.out.println(name);
}
}

2.png (176.93 KB, 下载次数: 84)

内存:堆,栈,方法区

内存:堆,栈,方法区
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马