我知道方法的局部变量和参数存在于堆栈中,但我无法弄清楚在 Java 的情况下方法实际存在于哪里?
如果我声明任何 Thread 对象,例如:
Thread t=new Thread();
t.start();
所以这意味着我已经创建了一个单独的方法调用,除了 main 方法。这是什么意思?这是否意味着在堆栈内存上调用单独的方法序列?我对吗?
我知道方法的局部变量和参数存在于堆栈中,但我无法弄清楚在 Java 的情况下方法实际存在于哪里?
如果我声明任何 Thread 对象,例如:
Thread t=new Thread();
t.start();
所以这意味着我已经创建了一个单独的方法调用,除了 main 方法。这是什么意思?这是否意味着在堆栈内存上调用单独的方法序列?我对吗?
每个线程都分配有自己的堆栈。
本文很好地介绍了 Java 进程中的内存分离。
在 Java 虚拟机内部,每个线程都被授予一个 Java 堆栈,其中包含其他线程无法访问的数据,包括该线程调用的每个方法的局部变量、参数和返回值。堆栈上的数据仅限于原始类型和对象引用。在 JVM 中,不可能将实际对象的图像放在堆栈上。所有对象都驻留在堆上。
我见过很多场景,客户端在每个线程执行的很少的基础上实现了大量线程的服务器,并且它们遇到了内存问题。那是因为每个线程都分配了自己的堆栈,并且(显然)加起来了。我认为默认值是每个线程 512k,但我还没有找到一个规范的来源。
如果我没记错的话,方法代码本身将存在于内存的代码部分,而内部声明的变量将存在于堆栈中,而对象将在堆上创建。在 Java 中,变量指针和原语存在于堆栈中,而任何创建的对象都存在于堆中。
对于(较差的)ASCII 表示:
-------
|STACK|
-------
|FREE |
-------
|HEAP |
-------
|CODE |
-------
其中STACK代表栈,FREE代表空闲内存,HEAP代表堆,CODE代表代码空间。
这就是我的记忆所说的——一些细节可能是错误的。
堆栈由方法调用组成。java压栈的是一个方法调用记录,它封装了该方法的所有变量(参数和本地实例化的变量)。当您启动 Java 应用程序时,main 方法(自动包含 args 参数)是堆栈上唯一的东西:
main(args)
当你创建一个 Foo 对象并调用 foo.method() 时,堆栈现在看起来像:
method()
main(args)
当方法被调用时,它们被压入堆栈,当它们返回时,它们被从堆栈中删除或“弹出”。随着变量的声明和使用,对应于当前方法(在堆栈顶部)的堆栈条目会增长到包含变量的大小。
对于您的线程示例,每个线程都有自己的堆栈,该堆栈独立于其他线程的堆栈而存在。
堆栈包含所有局部变量和所有活动方法调用。堆包含其他所有内容。
至于您的子问题:这意味着使用自己的专用内存创建了一个新堆栈。虽然您的新线程将共享 jvm 分配的总堆空间(内存)
堆被分成多代。
字节码及其对应的 JIT 编译机器代码与实习字符串和其他类数据一起存在于所谓的永久代中。
即使它被称为“永久”代,它仍然可以被垃圾收集。一些库、框架和 JVM 语言在运行时生成字节码,因此永久代有时需要清理。就像堆的其他几代一样,但(通常希望)不那么频繁。
实际的字节码和/或 JIT 代码将存在于进程的内存中。进程内存中可能只有一个副本,因为给定进程中的所有线程共享该内存。这些线程共享的任何变量都将由公共方法访问。线程的局部变量(甚至是线程中使用的方法局部变量)将在该线程的内存中创建。