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

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

© 郑昌奋 中级黑马   /  2013-3-23 14:51  /  1959 人查看  /  9 人回复  /   0 人收藏 转载请遵从CC协议 禁止商业使用本文

本帖最后由 郑昌奋 于 2013-3-23 15:58 编辑

堆和栈具体区别在哪儿?就是有些GC我们可以控制回收的吗?

点评

如果你的问题已经得到解决,请及时将主题改为[已解决],如果还有问题请继续追问,谢谢  发表于 2013-3-23 15:50

评分

参与人数 1技术分 +1 收起 理由
贾文泽 + 1

查看全部评分

9 个回复

倒序浏览
栈内存:用于存储局部变量,当数据使用完,所占空间会自动释放
堆内存:数组和对象,通过new建立实例存放在堆中,每个实体都有内存地址值
回复 使用道具 举报
堆中的数据多是不需要或者不能随意改变的,栈中多是变量,引用等,

可以人为的启动垃圾回收。
回复 使用道具 举报
本帖最后由 lixiaofeng 于 2013-3-23 15:29 编辑

java把内存划分成两种:一种是栈内存,一种是堆内存。

栈内存在函数中定义的一些基本类型的变量和对象的引用变量都在函数的栈内存中分配。当在一段代码块定义一个变量时,Java就在栈中为这个变量分配内存空间,当超过变量的作用域后,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。这样,就出现了ab同时均指向3的情况。这时,如果再令a=4;那么编译器会重新搜索栈中是否有4值,如果没有,则将4存放进来,并令a指向4;如果已经有了,则直接将a指向这个地址。因此a值的改变不会影响到b的值。要注意这种数据的共享与两个对象的引用同时指向一个对象的这种共享是不同的,因为这种情况a的修改并不会影响到b, 它是由编译器完成的,它有利于节省空间。而一个对象引用变量修改了这个对象的内部状态,会影响到另一个对象引用变量。

堆内存堆内存用来存放由new创建的对象和数组。在堆中分配的内存,由Java虚拟机的自动垃圾回收器来管理。在堆中产生了一个数组或对象后,还可以在栈中定义一个特殊的变量,让栈中这个变量的取值等于数组或对象在堆内存中的首地址,栈中的这个变量就成了数组或对象的引用变量。堆是一个运行时数据区,类的对象从中分配空间。这些对象通过newnewarrayanewarraymultianewarray等指令建立,它们不需要程序代码来显式的释放。堆是由垃圾回收来负责的,堆的优势是可以动态地分配内存大小,生存期也不必事先告诉编译器,因为它是在运行时动态分配内存的,Java的垃圾收集器会自动收走这些不再使用的数据。但缺点是,由于要在运行时动态分配内存,存取速度较慢。

评分

参与人数 1技术分 +1 收起 理由
贾文泽 + 1

查看全部评分

回复 使用道具 举报
VOIDMAIN 发表于 2013-3-23 15:17
堆中的数据多是不需要或者不能随意改变的,栈中多是变量,引用等,

可以人为的启动垃圾回收。 ...

那就是我们可以控制它回收的时间的吗?比如说,如果我设定一个计时器,当达到这个时间段的时候我就回收!
回复 使用道具 举报
回复 使用道具 举报
壁虎 中级黑马 2013-3-23 16:00:05
7#
本帖最后由 tuo1254 于 2013-3-23 16:02 编辑

首先回答楼主第一个问题:
问:堆和栈具体区别在哪儿?
1. 栈(stack)与堆(heap)都是Java用来在Ram中存放数据的地方。与C++不同,Java自动管理栈和堆,程序员不能直接地设置栈或堆。
2. 栈的优势是,存取速度比堆要快,仅次于直接位于CPU中的寄存器。但缺点是,存在栈中的数据大小与生存期必须是确定的,缺乏灵活性。另外,栈数据可以共享,堆的优势是可以动态地分配内存大小,生存期也不必事先告诉编译器,Java的垃圾收集器会自动收走这些不再使用的数据。但缺点是,由于要在运行时动态分配内存,存取速度较慢。
2.java必须要知道存储在栈中所有项的确切生命周期。以便通过上下移动栈指针来释放分配内存(栈指针若向上移动则释放那些内存,栈指针若向下移动则分配内存)
jvm为每个新创建的线程都分配一个栈。栈以帧为单位保存 线程的状态。jvm对栈只进行两种操作:以帧为单位的压栈和出栈 操作。
当线程激活一个java方法,jvm就会在线程的java栈里新压入一个帧。 这个帧自然成为了当前帧。在此方法执行期间,这个帧将用来保存参数, 局部变量,中
间计算过程和其他数据。java栈上的数据都是某个线程所私有的。这也就是为什么,当前线程无法访问到另一个线程中局部变量的原因。不过多线程却可以操作一个对象,因为对象是存在堆中的。
然后回答楼主第二个问题:
问:有些GC我们可以控制回收的吗?
答:Java是自动管理栈和堆。我们是不可以控制回收垃圾的回收。
在这里值得注意的是:垃圾回收不保证一定会发生,例如:new Student();//在这里我创建一个学生对象,但没有引用指向它,它便会被java中的垃圾回收器给回收,这并不是立刻就会被回收,因为java虚拟机没有面临内存耗尽的情形下,它是不会浪费时间去执行垃圾回收以恢复内存的。不过我们可以调用System.gc()方法来进行强制清理工作
回复 使用道具 举报
郑昌奋 发表于 2013-3-23 15:29
那就是我们可以控制它回收的时间的吗?比如说,如果我设定一个计时器,当达到这个时间段的时候我就回收! ...

可以啊,System.gc();
回复 使用道具 举报
郑昌奋 发表于 2013-3-23 15:29
那就是我们可以控制它回收的时间的吗?比如说,如果我设定一个计时器,当达到这个时间段的时候我就回收! ...

通常JRE会提供一个后台线程来进行检测和控制,一般都是在CPU空闲或者内存不足时自动进行垃圾回收,而程序员无法精确控制垃圾回收的时间和顺序;当堆里面的对象不再被引用时,内存回收它所占领的空间,所以需要回收堆里面的数据时可以把对象指向null。
回复 使用道具 举报
VOIDMAIN 发表于 2013-3-23 16:26
可以啊,System.gc();

调用后gc(), 这个方法是建议 JVM 进行垃圾回收,并不会马上进行垃圾回收,甚至不一定会执行垃圾回收.
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马