关于 js 与 Java 堆栈内存的一些疑惑

2017-04-26 14:02:49 +08:00
 peneazy

最近学习中遇到了些疑惑,希望 v2 各位大牛解惑。

先说 js ,限定在 ES5 讨论。在 js 中对象是存在堆内存中的,变量只是个引用,那对象的属性是存在哪的呢,假设该属性是个数字 3 ,函数作用域中的变量又是存在哪里呢。

再说 java , static 修饰的静态变量我理解为和 js 构造函数本身的属性是类似的东西,这东西存在哪块内存,局部变量存在哪块内存,类 new 出的对象中实例变量又存在哪里。

问题总结:下面两段 java 和 js 代码中, demo.num1 , DemoJava.num2 , num3 , num4 , obj1.num5 , arr1[0]都存在内存哪里?

public class DemoJava {
	public int num1 = 1;
	public static int num2 = 2;
	public static void main(String[] args) {
		DemoJava demo = new DemoJava();
		int num3 = 3;
		System.out.println("num1:" + demo.num1);
		System.out.println("num2:" + DemoJava.num2);
		System.out.println("num3:" + num3);
	}
}
var fun1, obj1, arr1;

function add() {
	var num4 = 4;
}

obj1 = {
	num5: 5
};

arr1 = [6, 7];
3110 次点击
所在节点    程序员
21 条回复
diangdiang
2017-04-26 14:42:26 +08:00
小白强行回答,貌似 java 类静态变量存在在方法区,局部变量存在栈,通过 new 生成的对象存在堆里,
《深入理解 Java 虚拟机》有详细介绍。
araraloren
2017-04-26 14:42:50 +08:00
~~很好奇
学 js/java 的人会对这个感兴趣么
murmur
2017-04-26 14:45:59 +08:00
如果是 java 的话其实不绝对,因为你不知道虚拟机把你的东西都优化到哪里去了。。。
peneazy
2017-04-26 15:03:44 +08:00
@diangdiang 也看到别人说有个方法区的地方
peneazy
2017-04-26 15:04:47 +08:00
@araraloren 没搞明白有些不舒服。。
peneazy
2017-04-26 15:05:35 +08:00
@murmur 原来是这样子啊
sagaxu
2017-04-26 15:18:37 +08:00
Java 的 Static 存在 Run-Time Constant Pool 里。但是知道它存哪里,毫无意义啊。
sagaxu
2017-04-26 15:22:32 +08:00
@peneazy Java 代码如何编译成字节码, JVM 又如何执行和优化, GC 具体是怎么工作的,这些全搞明白,可以读个博了。把 Java 搞懂了, Java 那么多框架和库,把细节搞明白一遍,没个二三十年恐怕不行。
gxbb097528
2017-04-26 16:47:32 +08:00
最近在看网易云课堂的 Java 基础视频,讲的有这些,但是讲的是大概,没有特别深究,要深究真跟楼上说的一样要几个好几年功夫,看看视频了解个大概还行
geelaw
2017-04-26 16:52:19 +08:00
纠结 JavaScript 的内存布局没有意义, JavaScript 把它抽象掉了。
guokeke
2017-04-26 17:31:24 +08:00
@geelaw +1
单从概念上理解,值类型用栈逻辑,引用类型用堆逻辑。
jun4rui
2017-04-26 17:38:12 +08:00
java 的类是引用类型,自然是在堆里面,所有同类共用一块地址
sagaxu
2017-04-26 17:45:45 +08:00
@jun4rui Java6 开始有了逃逸分析,对象未必会分配在堆上,可能会在栈上分配
peneazy
2017-04-26 19:00:07 +08:00
@sagaxu 果然是老司机
Ouyangan
2017-04-26 19:25:36 +08:00
@diangdiang #1 Java8 已经没持久代的概念了 , 也直接在堆上分配内存了.. 详情可以 google 下
jun4rui
2017-04-26 21:06:42 +08:00
```javascript
var fun1, obj1, arr1;

//对于 js 来说, function 这种引用值一般是保存在堆内存中的
function add() {
var num4 = 4;
}

//对象也是, js 中的对象一般是存放在堆内存。所以{num5:5}是保存在堆内存中
obj1 = {
num5: 5
};

//数组也是存放在堆内存
arr1 = [6, 7];
```

对于函数作用域应该还是这个标准, function 、 obj 、 array 是在堆,其他基本是在栈
phx13ye
2017-04-26 21:56:10 +08:00
实例基本类型和对象一起在堆
静态基本类型和 class 一起在 permgen 或 metaspace
方法基本类型和栈帧一起在栈
runjvm
2017-04-27 00:02:32 +08:00
前面很多同学说的都不太准确。
以 HotSpot 8 为例,静态变量并不存放在方法区或者 PermGen 或者 MetaSpace ,每一个类被解析后都有一个对应的 mirror 对象,这个对象是 java.lang.Class 类型,“方法区”存的只是元数据,譬如描述类的结构、各字段分别什么类型之类的,每一个类的元数据有个指针指向这个对应的 mirror 对象,静态变量是这个 mirror 对象的一个字段, mirror 对象不是只有那些静态变量对应的字段,它还有许多其他的字段用于 reflection 。而 mirror 对象其实都在堆上,于是静态变量作为其一个字段也在堆上。一个 Java 程序一旦运行其实最开始被分配的那些对象就是 primitive 类型对应的 mirror 对象。

所以短答案是,静态变量的元数据在方法区,但是静态本身在堆上。

至于前面同学说的逃逸分析,逃逸分析只在编译优化时发生,在解释器里 new 出来的实例对象总是在堆里。
okcdz
2017-04-27 01:03:16 +08:00
回答 js 的问题吧, java 不了解。你这个不是 es5 的问题,而是编译器的问题。对象保存在堆内存里面,对象属性也是。至于小整形,在 v8 实现里面是直接传递的,在 Chakra 里面也是保存在堆里面,然后引用传递。至于函数里的变量,那是运行时分配的空间,当然也是分配在堆里面的。
araraloren
2017-04-28 08:37:43 +08:00
@peneazy
但是这种已经隐藏了内部实现的语言,你纠结这个没什么用处
编译器 可以做各种它觉得可行的优化来提高你的程序执行效率,于是你说的各种情况都可能是片面的

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/357454

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX