读书人

Java 栈内存储器(Stack)

发布时间: 2013-10-31 12:03:52 作者: rapoo

Java 栈内存(Stack)

?

??????? 这里值得注意的是,堆的物理地址向高地址扩展,而栈的物理地址是向低地址扩展,压栈的操作使得栈顶的地址减小,弹出的操作使得栈顶的地址增大。


??????? 每一条JVM 线程都有自己私有的JVM 栈(Java Virtual Machine Stack),这个栈与线程同时创建,用于存储帧(Frames)。JVM 栈的作用与传统语言(例如C语言)中的栈非常类似,就是用于存储局部变量与一些过程结果的地方。另外,它在方法调用和返回中也扮演了很重要的角色。因为除了帧的出栈和入栈之外,JVM 栈不会再受其他因素的影响,所以帧可以在堆中分配,JVM 栈所使用的内存不需要保证是连续的。
??????? JVM 规范允许JVM 栈被实现成固定大小的或者是根据计算动态扩展和收缩的。如果采用固定大小的JVM 栈设计,那每一条线程的JVM 栈容量应当在线程创建的时候独立地选定。JVM 实现应当提供给程序员或者最终用户调节虚拟机栈初始容量的手段,对于可以动态扩展和收缩JVM 栈来说,则应当提供调节其最大、最小容量的手段。

??????? 虚拟机只会直接对Java 栈执行两种操作:以帧为单位的压栈与出栈。某个线程正在执行的方法被称为该线程的当前方法,当前方法使用的帧称为当前帧,当前方法所属的类称为当前类,当前类的常量池称为当前常量池。在线程执行一个方法时,它会跟踪当前类和当前常量池。
??????? 每当线程调用一个Java 方法时,虚拟机都会在该线程的Java 栈中压入一个新的帧,而这个帧自然就成为了当前帧。在执行这个方法时,他使用这个帧来存储参数,局部变量,中间运算结果等数据。
??????? Java方法可以以两种方式结束,一种为通过return 返回,称为正常返回;另一种为通过异常的抛出而中止。无论何种返回方式,虚拟机都会将当前帧弹出Java 栈然后释放掉,这样上一个方法的帧就成为了当前帧。
??????? Java 栈上的所有数据都是此线程私有的,任何线程都无法访问到另一个线程的栈内数据,所以我们不必去担心多线程下的帧数据同步问题。当一个线程调用一个方法时,方法的局部变量保存在调用线程Java 栈的帧中。只有调用方法的线程才能访问到那些局部变量信息。

???????Java代码

  1. public?static?int?method1(int?a,short?b,long?c,byte?d,Object?e){??
  2. ????return?0;??
  3. }??
  4. ??
  5. private?void?method2(long?f,double?g,Object?h){??
  6. ??
  7. }??

??????? 在局部变量区中各个参数的存储形式:


Java 栈内存储器(Stack)
?

??????? 在图中method2 方法中,局部变量数组第一个参数是reference(引用)类型,尽管我们在方法中没有声明这个参数,但是对于任何一个实例方法都是隐含加入的,他用来表示调用该方法的对象本身,也就是我们常用到的this 关键字。与此相反,method1却没有隐含这个变量,因为method1是一个static 芳芳,也就是类方法,类方法只与类本身有关,而与具体的对象无关,不能直接通过类方法访问类实例的变量,因为在方法调用的时候没有关联到一个具体实例。

??????? 前面已经提到类型为byte、short 和char 的值在存入数组前会被转换成int 值,在操作数栈中也是一样。前面文章提到过虚拟机并不直接支持boolean 类型,因此Java 编译器总是会用int 类型来表示boolean。其他类型是JVM 的基本类型,所以可以比较好的支持。他们在帧中是被当作int 来进行处理的,一旦他们被存回堆或方法区时,会被转换回原来的类型。
??????? 同样的,在Java 中,所有对象都按引用传递,并且都存储在堆中,永远都不会在局部变量区或操作数栈中存在,只会有他们的引用。
??????? 除了Java 方法的参数对于真正的局部变量可以任意觉得放置的顺序,例如在两个for 循环中都会用到int i的情况,当前一个for 循环执行完毕之后,局部变量i 已经超出了有效作用域,所以后面可以继续用i 来表示其他变量。

Java代码
  1. for(int?i=0;i<10;i++){??
  2. ????//TODO?Somthing??
  3. }??
  4. for(int?i=0;i<10;i++){??
  5. ????//TODO?Somthing??
  6. }??

?

???????Class代码
  1. 0:???iconst_99??????//int?a=99;??
  2. 1:???istore_0??
  3. 3:???iconst_100?????//int?b=100;??
  4. 4:???istore_1??
  5. 6:???iload_0??
  6. 7:???iload_1??
  7. 8:???iadd???????//a+b=199??
  8. 9:???istore_2??


?

???????Java代码

  1. public?class?StackTest?{??
  2. ??
  3. ????public?void?test()?{??
  4. ????????int?i1?=?5;??
  5. ????????int?i2?=?5;??
  6. ????????int?i3?=?6;??
  7. ????????int?i4?=?128;??
  8. ????????int?i5?=?32768;??
  9. ????}??
  10. }??

Shell代码

  1. javap?StackTest?-verbose?-c??

C代码

  1. Compiled?from?"StackTest.java"??
  2. public?class?StackTest?extends?java.lang.Object??
  3. ??SourceFile:?"StackTest.java"??
  4. ??minor?version:?0??
  5. ??major?version:?50??
  6. ??Constant?pool:??
  7. const?#1?=?class????????#2;?????//??StackTest??
  8. const?#2?=?Asciz????????StackTest;??
  9. const?#3?=?class????????#4;?????//??java/lang/Object??
  10. const?#4?=?Asciz????????java/lang/Object;??
  11. const?#5?=?Asciz????????<init>;??
  12. const?#6?=?Asciz????????()V;??
  13. const?#7?=?Asciz????????Code;??
  14. const?#8?=?Method???????#3.#9;??//??java/lang/Object."<init>":()V??
  15. const?#9?=?NameAndType??#5:#6;//??"<init>":()V??
  16. const?#10?=?Asciz???????LineNumberTable;??
  17. const?#11?=?Asciz???????LocalVariableTable;??
  18. const?#12?=?Asciz???????this;??
  19. const?#13?=?Asciz???????LStackTest;;??
  20. const?#14?=?Asciz???????test;??
  21. const?#15?=?int?32768;??
  22. const?#16?=?Asciz???????i1;??
  23. const?#17?=?Asciz???????I;??
  24. const?#18?=?Asciz???????i2;??
  25. const?#19?=?Asciz???????i3;??
  26. const?#20?=?Asciz???????i4;??
  27. const?#21?=?Asciz???????i5;??
  28. const?#22?=?Asciz???????SourceFile;??
  29. const?#23?=?Asciz???????StackTest.java;??
  30. ??
  31. {??
  32. public?StackTest();??
  33. ??Code:??
  34. ???Stack=1,?Locals=1,?Args_size=1??
  35. ???0:???aload_0??
  36. ???1:???invokespecial???#8;?//Method?java/lang/Object."<init>":()V??
  37. ???4:???return??
  38. ??LineNumberTable:??
  39. ???line?1:?0??
  40. ??
  41. ??LocalVariableTable:??
  42. ???Start??Length??Slot??Name???Signature??
  43. ???0??????5??????0????this???????LStackTest;??
  44. ??
  45. ??
  46. public?void?test();??
  47. ??Code:??
  48. ???Stack=1,?Locals=6,?Args_size=1??
  49. ???0:???iconst_5??????//将一个int?类型数据压入到操作数栈中??
  50. ???1:???istore_1??????//将i1?保存到局部变量表中??
  51. ??
  52. ???2:???iconst_5??????//将int?类型数据压入到操作数栈中??
  53. ???3:???istore_2??????//将i2?保存到局部变量表中??
  54. ??
  55. ???4:???bipush??6?????//将一个byte?类型数据入栈??
  56. ???6:???istore_3??????//将i3?保存到局部变量表中??
  57. ??
  58. ???7:???sipush??128???//将一个short?类型数据入栈??
  59. ???10:??istore??4?????//将i4?保存到局部变量表中??
  60. ??
  61. ???12:??ldc?????#15;??//从运行时常量池中提取数据推入操作数栈??
  62. ???14:??istore??5?????//将i5?保存到局部变量表中??
  63. ??
  64. ???16:??return????????//从当前方法返回void??
  65. ??LineNumberTable:??
  66. ???line?4:?0??
  67. ???line?5:?2??
  68. ???line?6:?4??
  69. ???line?7:?7??
  70. ???line?8:?12??
  71. ???line?9:?16??
  72. ??
  73. ??LocalVariableTable:??
  74. ???Start??Length??Slot??Name???Signature??
  75. ???0??????17??????0????this???????LStackTest;??
  76. ???2??????15??????1????i1???????I??
  77. ???4??????13??????2????i2???????I??
  78. ???7??????10??????3????i3???????I??
  79. ???12??????5??????4????i4???????I??
  80. ???16??????1??????5????i5???????I??
  81. }??

C代码

  1. lcd?#15??
  2. lcd?为操作码,#15为操作数??
  3. sipush??128??
  4. sipush?为操作码,128为操作数??


?

Java代码

  1. public?class?StackTest?{??
  2. ??
  3. ????public?void?test()?{??
  4. ????????String?str="str";??
  5. ????????String?str2="str";??
  6. ????}??
  7. }??

C代码

  1. Compiled?from?"StackTest.java"??
  2. public?class?StackTest?extends?java.lang.Object??
  3. ??SourceFile:?"StackTest.java"??
  4. ??minor?version:?0??
  5. ??major?version:?50??
  6. ??Constant?pool:??
  7. const?#1?=?class????????#2;?????//??StackTest??
  8. const?#2?=?Asciz????????StackTest;??
  9. const?#3?=?class????????#4;?????//??java/lang/Object??
  10. const?#4?=?Asciz????????java/lang/Object;??
  11. const?#5?=?Asciz????????<init>;??
  12. const?#6?=?Asciz????????()V;??
  13. const?#7?=?Asciz????????Code;??
  14. const?#8?=?Method???????#3.#9;??//??java/lang/Object."<init>":()V??
  15. const?#9?=?NameAndType??#5:#6;//??"<init>":()V??
  16. const?#10?=?Asciz???????LineNumberTable;??
  17. const?#11?=?Asciz???????LocalVariableTable;??
  18. const?#12?=?Asciz???????this;??
  19. const?#13?=?Asciz???????LStackTest;;??
  20. const?#14?=?Asciz???????test;??
  21. const?#15?=?String??????#16;????//??hello?world!??
  22. const?#16?=?Asciz???????hello?world!;??
  23. const?#17?=?Asciz???????str;??
  24. const?#18?=?Asciz???????Ljava/lang/String;;??
  25. const?#19?=?Asciz???????str2;??
  26. const?#20?=?Asciz???????SourceFile;??
  27. const?#21?=?Asciz???????StackTest.java;??
  28. ??
  29. {??
  30. public?StackTest();??
  31. ??Code:??
  32. ???Stack=1,?Locals=1,?Args_size=1??
  33. ???0:???aload_0??
  34. ???1:???invokespecial???#8;?//Method?java/lang/Object."<init>":()V??
  35. ???4:???return??
  36. ??LineNumberTable:??
  37. ???line?1:?0??
  38. ??
  39. ??LocalVariableTable:??
  40. ???Start??Length??Slot??Name???Signature??
  41. ???0??????5??????0????this???????LStackTest;??
  42. ??
  43. ??
  44. public?void?test();??
  45. ??Code:??
  46. ???Stack=1,?Locals=3,?Args_size=1??
  47. ???0:???ldc?????#15;?//String?hello?world!??
  48. ???2:???astore_1??
  49. ???3:???ldc?????#15;?//String?hello?world!??
  50. ???5:???astore_2??
  51. ???6:???return??
  52. ??LineNumberTable:??
  53. ???line?4:?0??
  54. ???line?5:?3??
  55. ???line?6:?6??
  56. ??
  57. ??LocalVariableTable:??
  58. ???Start??Length??Slot??Name???Signature??
  59. ???0??????7??????0????this???????LStackTest;??
  60. ???3??????4??????1????str???????Ljava/lang/String;??
  61. ???6??????1??????2????str2???????Ljava/lang/String;??
  62. ??
  63. }??

?

??????? 名词解释:
??????? class:代表类
??????? Method:代表方法
??????? Asciz:声明由JVM 调用,其他无法调用。
??????? Ljava/lang/String; JNI字段描述符,代表了String 类型对象。
??????? 更多解释可以参照JVM 规范。

???????

????????21-25行代码:声明了str 与str2 两个String 类型对象,并且只声明了一个字符串值"hello world!"。
????????47行代码:str 变量从常量池中提取#15 索引的值,这里就需要注意了,#15并不像前面那段代码那样直接存储的是值内容,而是指向#16的一个引用,所以返回给ldc 的就是一个引用类型数据。
????????48行代码:将str 的引用值保存到局部变量表中,astore_<n> 的作用就是将一个reference 类型数据保存到局部变量表中。
????????49行代码:此时的str2 变量直接从#15 索引这里获取了同str 变量一样的对象引用值,所以可以断定在同一个类或方法中,具有相同内容的String 类型对象持有的是相同的引用对象地址。
????????50行代码:将str2 的引用值保存到局部变量表中。


??????? 好了通过以上一些知识相信大家已经对JVM Stack 有了比较深的认识,从短短的一篇文章很难讲的全面,只能抓住一些重点来突出,更进一步的思考还需要在不同的实践中得到印证与结果。

?

读书人网 >编程

热点推荐