Java static变量保存在哪?

测试环境:

Microsoft Windows [版本 10.0.17134.165]
java -version
java version "1.8.0_171"
Java(TM) SE Runtime Environment (build 1.8.0_171-b11)
Java HotSpot(TM) 64-Bit Server VM (build 25.171-b11, mixed mode)

测试代码:

import java.io.IOException;

public class Main {
    private static String name = "lgh";
    private static int age = 26;

    public int fun() {
        try {
            System.out.println(name);
            System.out.println(age);
            return System.in.read();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return 0;
    }

    public static void main(String[] args) {
        new Main().fun();
    }
}

编译&运行:

D:\N3verL4nd\Desktop>javac Main.java

D:\N3verL4nd\Desktop>java -XX:+UseSerialGC -XX:-UseCompressedOops -Xms10m -Xmx10m Main
lgh
26

System.in.read() 的作用等同于断点。

使用 CLHSDB 连接:

// 查看进程 id
D:\>jps
5792 Jps
7932 Main

D:\>java -cp .;%JAVA_HOME%/lib/sa-jdi.jar sun.jvm.hotspot.CLHSDB
hsdb> attach 7932
Attaching to process 7932, please wait...

运行 universe

Heap Parameters:
Gen 0:   eden [0x0000000012600000,0x00000000127114d0,0x00000000128b0000) space capacity = 2818048, 39.7239507630814 used
  from [0x00000000128b0000,0x00000000128b0000,0x0000000012900000) space capacity = 327680, 0.0 used
  to   [0x0000000012900000,0x0000000012900000,0x0000000012950000) space capacity = 327680, 0.0 usedInvocations: 0

Gen 1:   old  [0x0000000012950000,0x0000000012950000,0x0000000013000000) space capacity = 7012352, 0.0 usedInvocations: 0

[eden] 0x00000000128b0000 - 0x0000000012600000 = 2B 0000(1260 0000)
[from] 0x0000000012900000 - 0x00000000128b0000 = 5 0000(120 0000)
[to] 0x0000000012950000 - 0x0000000012900000 = 5 0000(120 0000)

可以看到 eden:from:to 大致比例为8:1:1,可以看到新生代的[eden-from-to]内存是连续的。同时可以看新生代和老年代内存是连着的。大概和垃圾回收方式有关。

扫描我们的 Main 实例:

hsdb> scanoops 0x0000000012600000 0x00000000128b0000 Main
0x000000001270afd8 Main
hsdb> whatis 0x000000001270afd8
Address 0x000000001270afd8: In thread-local allocation buffer for thread "main" (1)  [0x0000000012703870,0x000000001270b6e8,0x00000000127114b8,{0x00000000127114d0})

hsdb> inspect 0x000000001270afd8
instance of Oop for Main @ 0x000000001270afd8 @ 0x000000001270afd8 (size = 16)
_mark: 1
_metadata._klass: InstanceKlass for Main
hsdb>

可见,Main 实例分配在了线程私有的 TLAB 中。
Main 类没有实例变量,所以他的大小是 16 字节,Mark Word + Klass 指针(64 位 JVM 关闭压缩指针的情况下)。

使用 inspect 命令没有显示出来 InstanceKlass 也就是类型指针的地址,据说是 HSDB 的bug。我们使用 mem 来获取更详细的信息。

hsdb> mem 0x000000001270afd8 2
0x000000001270afd8: 0x0000000000000001 // Mark Word
0x000000001270afe0: 0x0000000013400598 // 类型指针(与Mark Word 一起组成对象头)

由于 1 个十六进制位代表 4 个二进制位,所以以上 Mark Word 的最后一位 1 代表的二进制序列为0001。
这里写图片描述
也就是 Main 实例处在无锁状态。

查看该类型指针对应的数据:

hsdb> inspect 0x0000000013400598
Type is InstanceKlass (size of 440)
juint Klass::_super_check_offset: 48
Klass* Klass::_secondary_super_cache: Klass @ null
Array<Klass*>* Klass::_secondary_supers: Array<Klass*> @ 0x0000000013000f88
Klass* Klass::_primary_supers[0]: Klass @ 0x0000000013001c00
oop Klass::_java_mirror: Oop for java/lang/Class @ 0x0000000012709dc8 Oop for java/lang/Class @ 0x0000000012709dc8

或者使用 HSDB :
这里写图片描述

D:\Java\Tools\jol>java -XX:-UseCompressedOops -jar jol-cli.jar internals java.lang.Class
# Running 64-bit HotSpot VM.
# Objects are 8 bytes aligned.
# Field sizes by type: 8, 1, 1, 2, 2, 4, 4, 8, 8 [bytes]
# Array element sizes: 8, 1, 1, 2, 2, 4, 4, 8, 8 [bytes]

Failed to find matching constructor, falling back to class-only introspection.

java.lang.Class object internals:
 OFFSET  SIZE                                              TYPE DESCRIPTION                               VALUE
      0    16                                                   (object header)                           N/A
     16     8                     java.lang.reflect.Constructor Class.cachedConstructor                   N/A
     24     8                                   java.lang.Class Class.newInstanceCallerCache              N/A
     32     8                                  java.lang.String Class.name                                N/A
     40     8                                                   (alignment/padding gap)
     48     8                       java.lang.ref.SoftReference Class.reflectionData                      N/A
     56     8   sun.reflect.generics.repository.ClassRepository Class.genericInfo                         N/A
     64     8                                java.lang.Object[] Class.enumConstants                       N/A
     72     8                                     java.util.Map Class.enumConstantDirectory               N/A
     80     8                    java.lang.Class.AnnotationData Class.annotationData                      N/A
     88     8             sun.reflect.annotation.AnnotationType Class.annotationType                      N/A
     96     8                java.lang.ClassValue.ClassValueMap Class.classValueMap                       N/A
    104    40                                                   (alignment/padding gap)
    144     4                                               int Class.classRedefinedCount                 N/A
    148     4                                                   (loss due to the next object alignment)
Instance size: 152 bytes
Space losses: 48 bytes internal + 4 bytes external = 52 bytes total

使用 jol 获得 Class 对象的大小为 152,也就是 19 个字长。

hsdb> inspect 0x0000000012709dc8
instance of Oop for java/lang/Class @ 0x0000000012709dc8 @ 0x0000000012709dc8 (size = 176)
name: "lgh" @ 0x000000001270af80 Oop for java/lang/String @ 0x000000001270af80
age: 26
hsdb> mem 0x0000000012709dc8 22
0x0000000012709dc8: 0x0000002a139a5501 // 1
0x0000000012709dd0: 0x0000000013013ed0 // 2
0x0000000012709dd8: 0x0000000000000000 // 3
0x0000000012709de0: 0x0000000000000000 // 4
0x0000000012709de8: 0x0000000000000000 // 5
0x0000000012709df0: 0x00000000126e5348 // 6
0x0000000012709df8: 0x000000001270a4c8 // 7
0x0000000012709e00: 0x0000000000000000 // 8
0x0000000012709e08: 0x0000000000000000 // 9
0x0000000012709e10: 0x0000000000000000 // 10
0x0000000012709e18: 0x0000000000000000 // 11
0x0000000012709e20: 0x0000000000000000 // 12
0x0000000012709e28: 0x0000000000000000 // 13
0x0000000012709e30: 0x00000000127097d0 // 14
0x0000000012709e38: 0x0000000000000000 // 15
0x0000000012709e40: 0x0000000000000000 // 16
0x0000000012709e48: 0x0000000013400598 // 17 类型指针
0x0000000012709e50: 0x0000000000000000 // 18
0x0000000012709e58: 0x0000001600000000 // 19
0x0000000012709e60: 0x0000000000000001 // 20
0x0000000012709e68: 0x000000001270af80 // 21 "lgh" 的引用
0x0000000012709e70: 0x000000000000001a // 22 "26" 的 16 进制表示

可以看到 static 变量保存在 Class 实例的尾部。
Class 对象确实在堆中。
类型指针保存在 Class 实例 17 * 8 的位置上。

  • 46
    点赞
  • 115
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 17
    评论
### 回答1: 关键字 staticJava 表示静态的,它可以用来修饰类、方法和变量。被 static 修饰的类成员可以在不创建对象的情况下直接使用,也可以通过类名来访问。例如,可以通过类名来调用静态方法和访问静态变量。 ### 回答2: Javastatic关键字表示静态,它可以用于变量、方法和代码块。 对于变量而言,static修饰的变量是静态变量,也称为类变量。这意味着所有的对象共享同一个静态变量,无论创建多少个对象,只有一个静态变量的拷贝。静态变量在内存只会被分配一次,它属于类而不是对象。我们可以通过类名直接访问静态变量,无需实例化一个对象。 对于方法而言,static修饰的方法是静态方法,也称为类方法。与静态变量类似,静态方法属于类而不是对象,可以通过类名直接调用。与普通方法不同的是,静态方法不能操作非静态变量,因为非静态变量是属于对象的。 另外,static还可以用于代码块,静态代码块用static关键字修饰。静态代码块在类被加载时执行,并且只会执行一次。它可以用于执行一些初始化操作或加载资源。 总的来说,staticJava表示静态的概念,它可以用于变量、方法和代码块,使得它们属于类而不是对象。静态变量和静态方法可以通过类名直接访问和调用,而不需要实例化对象。静态代码块在类被加载时执行,并且只会执行一次。 ### 回答3: Javastatic是一个关键字,用于声明静态成员。静态成员是属于类的成员,而不是属于对象的成员。也就是说,它可以直接通过类名来访问,而无需实例化对象。 在Java,可以声明静态变量、静态方法和静态代码块。 首先,静态变量是在类级别上共享的变量,所有的对象共享同一个静态变量的值。它通常用于保存与类相关的常量或全局变量。对于静态变量,可以在类的任何地方进行访问和修改。 其次,静态方法是类级别上的方法,它不依赖于任何对象的状态,可以直接通过类名调用。静态方法通常用于实现与类相关的工具方法或公共方法。在静态方法,无法直接访问非静态成员,只能通过对象引用或者类名来访问。 最后,静态代码块是在类加载时执行的一段代码。它通常用于进行一些类级别的初始化操作,比如初始化静态变量或执行一些静态方法。静态代码块只会执行一次,且在类的第一次使用时被执行。 总而言之,Javastatic关键字用于声明静态成员,它可以通过类名直接访问,而无需实例化对象。静态成员包括静态变量、静态方法和静态代码块,它们在类级别上共享,通常用于保存常量或全局变量、实现工具方法和执行类级别的初始化操作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 17
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

N3verL4nd

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值