前言有时候只有理解了代码的底层原理,才能真正的理解代码,就例如递归这些思想,理解了底层后就会很简单,这篇文章我会先谈内存的运行机制再通过底层谈谈作用域的问题
java数据区分类首先当我们运行一个java程序的时候,我们的java虚拟机会将内存分为:栈内存,堆内存,方法区,本地方法栈,程序计数器 如上图,下面详细的说一下栈内存,堆内存,方法区
栈内存每当启动一个新线程(调用一个函数)的时候,java虚拟机都会为它分配一个java栈。java以栈帧为单位保存线程的运行状态。虚拟机只会对java栈执行两种 *** 作:以栈帧为单位的压栈或者出栈。
每个线程包含一个栈区,栈中只保存基础数据类型的对象和自定义对象的引用(不是对象),对象都存放在堆区中 。
每个栈中的数据(原始类型和对象引用)都是私有的,其他栈不能访问。
总结来说的话就是每调用一个函数就会再栈内存中开辟处一下块地址,我们称之为栈帧,每个栈帧都保存者自己的变量,外界无法访问,只有当当前的函数执行完后栈帧才会被释放,一个栈帧随着一个方法的调用开始而创建,这个方法调用完成而销毁。栈帧内存放者方法中的局部变量, *** 作数栈等数据。
由上图可以看出,Java栈中存放的是一个个的栈帧,每个栈帧对应一个被调用的方法,在栈帧中包括局部变量表(Local Variables)、 *** 作数栈(Operand Stack)、指向当前方法所属的类的运行时常量池(运行时常量池的概念在方法区部分会谈到)的引用(Reference to runtime constant pool)、方法返回地址(Return Address)和一些额外的附加信息。当线程执行一个方法时,就会随之创建一个对应的栈帧,并将建立的栈帧压栈。当方法执行完毕之后,便会将栈帧出栈。因此可知,线程当前执行的方法所对应的栈帧必定位于Java栈的顶部。
存储的是对象和数组本生,jvm只有一个堆区(heap)被所有线程共享,堆区中不存放基本类型和对象引用
堆的优势是可以动态地分配内存大小,生存期也不必事先告诉编译器,因为它是在运行时动态分配内存的,Java的垃圾收集器会自动收走这些不再使用的数据。
缺点是,由于要在运行时动态分配内存,存取速度较慢。
在方法区中,存储了每个类的信息(包括类的名称、方法信息、字段信息)、静态变量、常量以及编译器编译后的代码等。
在Class文件中除了类的字段、方法、接口等描述信息外,还有一项信息是常量池,用来存储编译期间生成的字面量和符号引用。
在方法区中有一个非常重要的部分就是运行时常量池,它是每一个类或接口的常量池的运行时表示形式,在类和接口被加载到JVM后,对应的运行时常量池就被创建出来。
当然并非Class文件常量池中的内容才能进入运行时常量池,在运行期间也可将新的常量放入运行时常量池中,比如String的intern方法。虽然JVM规范把方法区描述为堆的一个逻辑部分, 但它却有个别名non-heap(非堆)。
作用域- 对于在作用域里定义的变量,作用域同时决定了它的“可见性”以及“存在时间”。在JAVA里,作用域是由花括号的位置决定的。JAVA用一对大括号作为语句块的范围,称为作用域,在作用域里定义的变量,只有在该作用域结束之前才可使用。
说明:
* 方法内部除了能访问方法级的变量,还可以访问类级和实例级的变量。
* 块内部能够访问类级、实例级变量,如果块被包含在方法内部,它还可以访问方法级的变量。
在Java语言中,变量的类型主要有3种:
全局变量或类变量,成员变量,局部变量
全局变量:类级变量又称全局级变量或静态变量,需要使用static关键字修饰,因为全局便改良保存在方法存中,所用的栈帧都可以访问所以全局变量的作用范围是整个函数
成员变量:类的成员变量的作用范围与类的实例化对象的作用范围相同,当类被实例化时,成员变量就会在内存中分配空间并初始化,直到这个被实例化对象的生命周期结束时,成员变量的生命周期才结束。
局部变量:因为局部变量之存在与栈帧中所以外界无法访问局部变量
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)