黑马程序员技术交流社区

标题: 对于毕老师说的内存划分,表示很郁闷。求解释 [打印本页]

作者: 王勃    时间: 2012-4-24 07:27
标题: 对于毕老师说的内存划分,表示很郁闷。求解释
本帖最后由 王明(1988) 于 2012-4-24 08:29 编辑

之前学习过组成原理,也做过反汇编破解和木马免杀的事,脑子里一直都是这样的内存划分:
1、堆 (自由存储区,C,C++堆里的内存是需要程序员亲自释放的,否则出现空指针造成内存泄露,当然java有垃圾回收机制,就不多说了。共同的是new的对象放在这里)
2、栈(由编译器自动分配释放,存放函数的参数值,局部变量的值等,具体方法执行结束之后,系统自动释放内存资源)
3、数据区(data segment)— 存放全局变量,静态变量 和字符串常量,不释放。
4、代码区(code segment)— 存放程序中方法的二进制代码,而且是多个对象 共享一个代码空间区域 ,通常类中的成员方法都放在这里,只是安静的存在,并未执行执行时,才到栈中申请
      局部变量的内存空间进行一系列操作。

注:在方法(代码块)中定义一个变量时,java 就在栈中为这个变量分配内存空间,当超过变量的作用域后,java 会自动释放掉为该变量所分配的内存空间。

而毕向东老师的视频中总是将数据区(也叫数据段data segment,在学黑客时养的习惯)叫做方法区,说方法区存放静态变量,字符串常量。。
既然是放变量常量的地方,为什么用方法区命名,之前看过尚学堂马士兵的java视频他讲的和我说的一样。上个图证明下:

我表示很郁闷啊。。。求个解释,谢谢。{:soso_e144:}
作者: 王勃    时间: 2012-4-24 09:39
怎么还没人呢,求解释,求说明。求统一内存分块概念
作者: 冯佳老师    时间: 2012-4-24 13:31
Java内存共划分5片内存区:
1,堆内存 :存储对象。垃圾回收
2,栈内存 :局部变量数据。所属区域结束释放。
3,方法区 :代码表,静态区,常量池等,可以成为数据共享区。因为生命周期长。
4,本地方法区 :和系统相关,jvm对系统底层进行调用,比如调用C的代码。
5,寄存器 : 和处理器相关。

C语言的内存划分是你说的划分方式。

作者: 耿少雄    时间: 2012-4-24 13:47
JVM的内存,被划分了很多的区域:

1.程序计数器
每一个Java线程都有一个程序计数器来用于保存程序执行到当前方法的哪一个指令。
2.线程栈
线程的每个方法被执行的时候,都会同时创建一个帧(Frame)用于存储本地变量表、操作栈、动态链接、方法出入口等信息。每一个方法的调用至完成,就意味着一个帧在VM栈中的入栈至出栈的过程。如果线程请求的栈深度大于虚拟机所允许的深度,将抛出StackOverflowError异常;如果VM栈可以动态扩展(VM Spec中允许固定长度的VM栈),当扩展时无法申请到足够内存则抛出OutOfMemoryError异常。
3.本地方法栈
4.堆
每个线程的栈都是该线程私有的,堆则是所有线程共享的。当我们new一个对象时,该对象就被分配到了堆中。但是堆,并不是一个简单的概念,堆区又划分了很多区域,为什么堆划分成这么多区域,这是为了JVM的内存垃圾收集,似乎越扯越远了,扯到垃圾收集了,现在的jvm的gc都是按代收集,堆区大致被分为三大块:新生代,旧生代,持久代(虚拟的);新生代又分为eden区,s0区,s1区。新建一个对象时,基本小的对象,生命周期短的对象都会放在新生代的eden区中,eden区满时,有一个小范围的gc(minor gc),整个新生代满时,会有一个大范围的gc(major gc),将新生代里的部分对象转到旧生代里。
5.方法区
其实就是永久代(Permanent Generation),方法区中存放了每个Class的结构信息,包括常量池、字段描述、方法描述等等。VM Space描述中对这个区域的限制非常宽松,除了和Java堆一样不需要连续的内存,也可以选择固定大小或者可扩展外,甚至可以选择不实现垃圾收集。相对来说,垃圾收集行为在这个区域是相对比较少发生的,但并不是某些描述那样永久代不会发生GC(至 少对当前主流的商业JVM实现来说是如此),这里的GC主要是对常量池的回收和对类的卸载,虽然回收的“成绩”一般也比较差强人意,尤其是类卸载,条件相当苛刻。
6.常量池
Class文件中除了有类的版本、字段、方法、接口等描述等信息外,还有一项信息是常量表(constant_pool table),用于存放编译期已可知的常量,这部分内容将在类加载后进入方法区(永久代)存放。但是Java语言并不要求常量一定只有编译期预置入Class的常量表的内容才能进入方法区常量池,运行期间也可将新内容放入常量池(最典型的String.intern()方法)。
作者: 马伟恒    时间: 2012-4-24 15:53
Java 中的堆和栈
 Java把内存划分成两种:一种是栈内存,一种是堆内存。
   在函数中定义的一些基本类型的变量和对象的引用变量都在函数的栈内存中分配。
    当在一段代码块定义一个变量时,Java就在栈中为这个变量分配内存空间,当超过变量的作用域后,Java会自动释放掉为该变量所分配的内存空间,该内存空间可以立即被另作他用。
   堆内存用来存放由new创建的对象和数组。在堆中分配的内存,由Java虚拟机的自动垃圾回收器来管理。
   在堆中产生了一个数组或对象后,还可以在栈中定义一个特殊的变量,让栈中这个变量的取值等于数组或对象在堆内存中的首地址,栈中的这个变量就成了数组或对象的引用变量。
   引用变量就相当于是为数组或对象起的一个名称,以后就可以在程序中使用栈中的引用变量来访问堆中的数组或对象。
具体的说:
 栈与堆都是Java用来在Ram中存放数据的地方。与C++不同,Java自动管理栈和堆,程序员不能直接地设置栈或堆。
Java的堆是一个运行时数据区,类的(对象从中分配空间。这些对象通过new、newarray、anewarray和 multianewarray等指令建立,它们不需要程序代码来显式的释放。堆是由垃圾回收来  负责的,堆的优势是可以动态地分配内存大小,生存期也不必事先告诉编译器,因为它是在运行时动态分配内存的,Java的垃圾收集器会自动收走这些不再使用的数据。但缺点是,由于要在运行时动态分配内存,存取速度较慢。
  栈的优势是,存取速度比堆要快,仅次于寄存器,栈数据可以共享。但缺点是,存在栈中的数据大小与生存期必须是确定的,缺乏灵活性。栈中主要存放一些基本类型的变量(,int, short, long, byte, float, double, boolean, char)和对象句柄。
栈有一个很重要的特殊性,就是存在栈中的数据可以共享。假设我们同时定义:
int a = 3;
int b = 3;
   编译器先处理int a = 3;首先它会在栈中创建一个变量为a的引用,然后查找栈中是否有3这个值,如果没找到,就将3存放进来,然后将a指向3。接着处理int b = 3;在创建完b的引用变量后,因为在栈中已经有3这个值,便将b直接指向3。这样,就出现了a与b同时均指向3的情况。这时,如果再令a=4;那么编译器会重新搜索栈中是否有4值,如果没有,则将4存放进来,并令a指向4;如果已经有了,则直接将a指向这个地址。因此a值的改变不会影响到b的值。要注意这种数据的共享与两个对象的引用同时指向一个对象的这种共享是不同的,因为这种情况a的修改并不会影响到b, 它是由编译器完成的,它有利于节省空间。而一个对象引用变量修改了这个对象的内部状态,会影响到另一个对象引用变量。

作者: 咋还起名    时间: 2012-8-14 07:39
111111111111111111111111111111111111111




欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2