Java内存结构
程序计数器是jvm执行程序的流水线,存放一些跳转指令,和记录当前线程执行的位置。 本地方法栈是jvm调用操作系统方法所使用的栈。 虚拟机栈是jvm执行java代码所使用的栈。 为了保证线程中的局部变量不被别的线程访问到,虚拟机栈和本地方法栈是线程私有的。 方法区(元空间)存放了一些常量、静态变量、类信息等,可以理解成class文件在内存中的存放位置。 虚拟机堆是jvm执行java代码所使用的堆。
注:图中方法区的class是.class字节码转换后的运行区数据结构,而不是Class对象
- 局部变量和方法参数在jvm中的储存方法是相同的,都是在栈上开辟空间来储存的,随着进入方法开辟,退出方法回收。
- 每个线程都分配一个独享的stack,所有线程共享一个heap。对于每个方法的局部变量来说,是绝对无法被其他方法,甚至其他线程的同一方法所访问到。
值传递和引用传递
Java 到底是值传递还是引用传递?
Java是按值传递。参数传递基本上就是赋值操作,基本类型传的本身的值,引用类型传的是堆里的地址(可当做值)。
我的理解:两个栈空间引用同一地址只能说明他们对应的地址值相同,而不代表他们的引用永远绑定在一起(如果是按引用传递,那么就是这么个情况),只要对其中一个栈空间重新赋值,就会在堆中开辟新的内存地址,引用这个新的地址。
JavaScript也是按值传递
=>StringBuilder sb = new StringBuilder("iphone");
void foo(StringBuilder builder) {
builder = new StringBuilder("ipad");
}
foo(sb); // sb 没有被改变,还是 "iphone"
如果是按引用传递
=>常量池
深入浅出Java常量池精
Java中的常量池:静态常量池(.class文件中)和运行时常量池(方法区)。
常量池是为了避免频繁的创建和销毁对象而影响系统性能,其实现了对象的共享。字符串常量池
例如字符串常量池,在编译阶段就把所有的字符串文字放到一个常量池中。
(1)节省内存空间:常量池中所有相同的字符串常量被合并,只占用一个空间。
(2)节省运行时间:比较字符串时,==比equals()快。对于两个引用变量,只用==判断引用是否相等,也就可以判断实际值是否相等。
- 字面量、字面量拼接后的结果,会放进静态常量池和运行时常量池
- 含有new String()拼接或变量拼接的字符串会在堆中产生,不会和方法区常量池等值的字符串地址相同
数值类型常量池
数值类型的常量池不可以手动添加常量,程序启动时常量池中的常量就已经确定了,比如整型常量池中的常量范围:-128~127,(Byte,Short,Integer,Long,Character,Boolean)这5种包装类默认创建了数值[-128,127]的相应类型的缓存数据(堆中),但是超出此范围仍然会去创建新的对象。例如在自动装箱时,把int变成Integer的时候,首先去缓存中找,找到的话直接返回引用给你就 行了,不必再新new一个),如果不在-128-IntegerCache.high(127) 时会返回一个新new出来的Integer对象。gc
没有被任何引用所指向的对象是垃圾,会被垃圾回收器回收
查看当前服务器垃圾回收机制java -XX:+PrintCommandLineFlags -version
反编译
jd-gui
jad 不准