方法存储在哪里?堆栈还是堆中?

4

我知道本地变量和方法参数存在堆栈中,但是我无法确定Java中的方法实际上存在于哪里?

如果我声明任何线程对象,比如:

Thread t=new Thread();
t.start();

所以这意味着我已经创建了一个与主方法分开的方法调用。这是什么意思?它是否意味着在堆栈内存上调用单独的方法序列?我的理解正确吗?


3
你这样的表达方式让我感到不舒服。"Method" "Lives"在代码空间中,它不在堆栈或堆上。在堆上创建一个对象,该对象有指向其每个方法的指针。该对象存放在堆中,但它所指向的方法存在于代码中。 - Bill K
6个回答

8

如果我没记错的话,方法代码本身将存储于内存的代码区域,而内部声明的变量将存储于堆栈中,对象将被创建于堆中。在Java中,变量指针和基本类型将存储于堆栈中,而任何创建的对象将存储于堆中。

一个(不好的)ASCII表示:

-------
|STACK|
-------
|FREE |
-------
|HEAP |
-------
|CODE |
-------

其中,STACK代表栈,FREE代表空闲内存,HEAP代表堆,CODE代表代码空间。

这是我的记忆 - 一些细节可能不正确。


正如Brian Agnew所指出的那样,每个进程都有自己的堆栈,而它们共享堆空间。 - aperkins

8
每个线程都被分配了自己的堆栈。
这篇文章很好地介绍了Java进程内存分离。
在Java虚拟机内部,每个线程都被授予一个Java堆栈,其中包含其他线程无法访问的数据,包括线程调用的每个方法的局部变量、参数和返回值。堆栈上的数据仅限于基本类型和对象引用。在JVM中,不可能将实际对象的映像放置在堆栈上。所有对象都驻留在堆上。
我见过很多情况,客户端在每个线程执行的任务非常少的情况下实现了大规模的线程服务器,并遇到了内存问题。这是因为每个线程都被分配了自己的堆栈,这(显然)会累加。我认为默认值是每个线程512k,但我没有找到官方的来源。

6

栈由方法调用组成。Java 将方法调用记录推入栈中,该记录封装了该方法的所有变量(包括参数和本地实例化变量)。当您启动 Java 应用程序时,主方法(自动包括 args 参数)是栈上唯一的东西:

main(args)

当你创建一个Foo对象并调用foo.method()时,堆栈现在看起来像这样:
method()
main(args)

随着方法的调用,它们会被推入栈中,当它们返回时,它们将从栈中移除或“弹出”。随着变量的声明和使用,与当前方法对应的栈条目(位于栈顶部)的大小将增加以包括变量的大小。
对于您的线程示例,每个线程都将有自己的堆栈,这些堆栈独立于其他线程的堆栈存在。

2

栈包含所有本地变量和所有活动的方法调用。堆则保存其他所有内容。

至于您的子问题:它意味着将创建一个具有自己专用内存的新栈。而您的新线程将共享jvm分配的总堆空间(内存)。


我非常确定堆栈包含所有本地基本变量和指向实际对象的指针(实际上是引用)。 - sixtyfootersdude

1

堆被分成多个代。

字节码及其对应的JIT编译后的机器码存储在所谓的永久代中,与字符串和其他类数据一起。

尽管它被称为“永久”代,但它仍然可以进行垃圾回收。一些库、框架和JVM语言会在运行时生成字节码,因此永久代有时需要清理。就像堆的其他代一样,但(通常希望)不太频繁。


0
实际的字节码和/或JIT编译后的代码将存储在进程的内存中。在进程内存中可能只有一个副本,因为给定进程中的所有线程共享该内存。由这些线程共享的任何变量将被公共方法访问。线程本地变量(甚至是在线程内使用的方法本地变量)将在该线程的内存中创建。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接