JVM_3_类文件结构

本文详细解析了Java类文件的结构,包括魔数、版本、常量池、访问标识、继承信息、Field和Method信息,以及附加属性。通过一个HelloWorld类的实例,展示了类文件中各项内容的表示方式,如方法名、参数描述和源文件信息等。

概述

  1. 类文件结构
  2. 字节码指令
  3. 编译期处理
  4. 类加载阶段
  5. 类加载器
  6. 运行期优化

image-20210916170230617

类文件结构

一个简单的HelloWorld.java

package cn.chasing.jvm.t3
// HelloWorld示例
public class HelloWorld {
  public static void main(String[] args) {
    System.out.println("hello world");
  }
}

执行

javac -parameters -d . HelloWorld.java

编译为HelloWorld.class后是这个样子,以八进制表示

image-20210916171510631

根据JVM规范,类文件结构如下

image-20210916171720756

魔数

0~3字节,表示它是否是【class】类型文件

image-20210916171831240

版本

4~7字节,表示类的版本00 32 (52) 表示是java8

image-20210916171939687

常量池

Constant TypeValue
CONSTANT_Class7
CONSTANT_Fieldref9
CONSTANT_Methodref10
CONSTANT_InterfaceMethodref11
CONSTANT_String8
CONSTANT_Integer3
CONSTANT_Float4
CONSTANT_Long5
CONSTANT_Double6
CONSTANT_NameAndType12
CONSTANT_Utf81
CONSTANT_MethodHandle15
CONSTANT_MethodType16
CONSTANT_InvokeDynamic18

8~9 字节,表示常量池长度,00 23 (35) 表示常量池有 #1~#34项,注意 #0 项不计入,也没有值

image-20210916173119340

第#1项 0a 表示一个 Method 信息,00 06 和 00 15(21) 表示它引用了常量池中 #6 和 #21 项来获得这个方法的【所属类】和【方法名】

image-20210916173148592

第#2项 09 表示一个 Field 信息,00 16(22)和 00 17(23) 表示它引用了常量池中 #22 和 # 23 项来获得这个成员变量的【所属类】和【成员变量名】

image-20210916173216154

第#3项 08 表示一个字符串常量名称,00 18(24)表示它引用了常量池中 #24 项

image-20210916173250860

第#4项 0a 表示一个 Method 信息,00 19(25) 和 00 1a(26) 表示它引用了常量池中 #25 和 #26项来获得这个方法的【所属类】和【方法名】

image-20210916173325154

第#5项 07 表示一个 Class 信息,00 1b(27) 表示它引用了常量池中 #27 项

image-20210916173345710

第#6项 07 表示一个 Class 信息,00 1c(28) 表示它引用了常量池中 #28 项

image-20210916173407099

第#7项 01 表示一个 utf8 串,00 06 表示长度,3c 69 6e 69 74 3e 是【 】,构造方法

image-20210916173432845

第#8项 01 表示一个 utf8 串,00 03 表示长度,28 29 56 是【()V】其实就是表示无参、无返回值

image-20210916173456434

第#9项 01 表示一个 utf8 串,00 04 表示长度,43 6f 64 65 是【Code】

image-20210916173517588

第#10项 01 表示一个 utf8 串,00 0f(15) 表示长度,4c 69 6e 65 4e 75 6d 62 65 72 54 61 62 6c 65是【LineNumberTable】

image-20210916173538432

第#11项 01 表示一个 utf8 串,00 12(18) 表示长度,4c 6f 63 61 6c 56 61 72 69 61 62 6c 65 54 61 62 6c 65是【LocalVariableTable】

image-20210916173603360

第#12项 01 表示一个 utf8 串,00 04 表示长度,74 68 69 73 是【this】

image-20210916173637222

第#13项 01 表示一个 utf8 串,00 1d(29) 表示长度,是【Lcn/itcast/jvm/t5/HelloWorld;】

image-20210916173711333

第#14项 01 表示一个 utf8 串,00 04 表示长度,74 68 69 73 是【main】

image-20210916173734208

第#15项 01 表示一个 utf8 串,00 16(22) 表示长度,是【([Ljava/lang/String;)V】其实就是参数为字符串数组,无返回值

image-20210916173807065

第#16项 01 表示一个 utf8 串,00 04 表示长度,是【args】

image-20210916173826344

第#17项 01 表示一个 utf8 串,00 13(19) 表示长度,是【[Ljava/lang/String;】

image-20210916173859368

第#18项 01 表示一个 utf8 串,00 10(16) 表示长度,是【MethodParameters】

image-20210916173938450

第#19项 01 表示一个 utf8 串,00 0a(10) 表示长度,是【SourceFile】

image-20210916173956339

第#20项 01 表示一个 utf8 串,00 0f(15) 表示长度,是【HelloWorld.java】

image-20210916174015532

第#21项 0c 表示一个 【名+类型】,00 07 00 08 引用了常量池中 #7 #8 两项

image-20210916174033651

第#22项 07 表示一个 Class 信息,00 1d(29) 引用了常量池中 #29 项

image-20210916174052536

第#23项 0c 表示一个 【名+类型】,00 1e(30) 00 1f (31)引用了常量池中 #30 #31 两项

image-20210916174115838

第#24项 01 表示一个 utf8 串,00 0f(15) 表示长度,是【hello world】

image-20210916174137320

第#25项 07 表示一个 Class 信息,00 20(32) 引用了常量池中 #32 项

image-20210916174155804

第#26项 0c 表示一个 【名+类型】,00 21(33) 00 22(34)引用了常量池中 #33 #34 两项

image-20210916174214126

第#27项 01 表示一个 utf8 串,00 1b(27) 表示长度,是【cn/itcast/jvm/t5/HelloWorld】

image-20210916174230106

第#28项 01 表示一个 utf8 串,00 10(16) 表示长度,是【java/lang/Object】

image-20210916174251996

第#29项 01 表示一个 utf8 串,00 10(16) 表示长度,是【java/lang/System】

image-20210916174308792

第#30项 01 表示一个 utf8 串,00 03 表示长度,是【out】

image-20210916174325894

第#31项 01 表示一个 utf8 串,00 15(21) 表示长度,是【Ljava/io/PrintStream;】

image-20210916174344994

第#32项 01 表示一个 utf8 串,00 13(19) 表示长度,是【java/io/PrintStream】

image-20210916174402268

第#33项 01 表示一个 utf8 串,00 07 表示长度,是【println】

image-20210916174422858

第#34项 01 表示一个 utf8 串,00 15(21) 表示长度,是【(Ljava/lang/String;)V】

image-20210916174443412

访问标识与继承信息

image-20210916190305559

image-20210916190329231

Field 信息

image-20210916190356535

image-20210916190409974

Method 信息

image-20210916190450989

一个方法由 访问修饰符,名称,参数描述,方法属性数量,方法属性组成

  • 红色代表访问修饰符(本类中是 public)

  • 蓝色代表引用了常量池 #07 项作为方法名称

  • 绿色代表引用了常量池 #08 项作为方法参数描述

  • 黄色代表方法属性数量,本方法是 1

  • 红色代表方法属性

    • 00 09 表示引用了常量池 #09 项,发现是【Code】属性

    • 00 00 00 2f 表示此属性的长度是 47

    • 00 01 表示【操作数栈】最大深度

    • 00 01 表示【局部变量表】最大槽(slot)数

    • 2a b7 00 01 b1 是字节码指令

    • 00 00 00 02 表示方法细节属性数量,本例是 2

    • 00 0a 表示引用了常量池 #10 项,发现是【LineNumberTable】属性

      • 00 00 00 06 表示此属性的总长度,本例是 6
      • 00 01 表示【LineNumberTable】长度
      • 00 00 表示【字节码】行号 00 04 表示【java 源码】行号
    • 00 0b 表示引用了常量池 #11 项,发现是【LocalVariableTable】属性

      • 00 00 00 0c 表示此属性的总长度,本例是 12
      • 00 01 表示【LocalVariableTable】长度
      • 00 00 表示局部变量生命周期开始,相对于字节码的偏移量
      • 00 05 表示局部变量覆盖的范围长度
      • 00 0c 表示局部变量名称,本例引用了常量池 #12 项,是【this】
      • 00 0d 表示局部变量的类型,本例引用了常量池 #13 项,是【Lcn/itcast/jvm/t5/HelloWorld;】
      • 00 00 表示局部变量占有的槽位(slot)编号,本例是 0

image-20210916190830059

  • 红色代表访问修饰符(本类中是 public static)

  • 蓝色代表引用了常量池 #14 项作为方法名称

  • 绿色代表引用了常量池 #15 项作为方法参数描述

  • 黄色代表方法属性数量,本方法是 2

  • 红色代表方法属性(属性1)

    • 00 09 表示引用了常量池 #09 项,发现是【Code】属性
    • 00 00 00 37 表示此属性的长度是 55
    • 00 02 表示【操作数栈】最大深度
    • 00 01 表示【局部变量表】最大槽(slot)数
    • 00 00 00 09 表示字节码长度,本例是 9
    • b2 00 02 12 03 b6 00 04 b1 是字节码指令
    • 00 00 00 02 表示方法细节属性数量,本例是 2
    • 00 0a 表示引用了常量池 #10 项,发现是【LineNumberTable】属性
      • 00 00 00 0a 表示此属性的总长度,本例是 10
      • 00 02 表示【LineNumberTable】长度
      • 00 00 表示【字节码】行号 00 06 表示【java 源码】行号
      • 00 08 表示【字节码】行号 00 07 表示【java 源码】行号
    • 00 0b 表示引用了常量池 #11 项,发现是【LocalVariableTable】属性
      • 00 00 00 0c 表示此属性的总长度,本例是 12
      • 00 01 表示【LocalVariableTable】长度
      • 00 10 表示局部变量名称,本例引用了常量池 #16 项,是【args】
      • 00 11 表示局部变量的类型,本例引用了常量池 #17 项,是【[Ljava/lang/String;】
      • 00 00 表示局部变量占有的槽位(slot)编号,本例是 0

image-20210916191101579

红色代表方法属性(属性2)

  • 00 12 表示引用了常量池 #18 项,发现是【MethodParameters】属性
    • 00 00 00 05 表示此属性的总长度,本例是 5
    • 01 参数数量
    • 00 10 表示引用了常量池 #16 项,是【args】
    • 00 00 访问修饰符

image-20210916191158906

附加属性

  • 00 01 表示附加属性数量
  • 00 13 表示引用了常量池 #19 项,即【SourceFile】
  • 00 00 00 02 表示此属性的长度
  • 00 14 表示引用了常量池 #20 项,即【HelloWorld.java】

image-20210916191237721

参考文献

https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html

<think>好的,我现在需要帮助用户在Kubernetes中监控Cassandra的JVM堆内存和最大堆内存指标,也就是cass_jvm_heap和cass_jvm_heap_max。用户之前的问题是关于查看和修改K8s的内存配置,现在转向监控Cassandra的JVM相关指标。我需要结合之前的引用内容来构建解决方案。首先,我得回顾用户提供的引用内容。引用[1]提到Cassandra的堆外内存管理,引用[2]关于Prometheus和Grafana的配置,引用[3]详细解释了JVM的内存结构,引用[4]涉及JVM堆内存的大小限制。这些引用可能对解决问题有帮助。用户的目标是监控Cassandra的JVM堆内存,所以需要确保Cassandra的JVM暴露这些指标。通常,Java应用可以通过JMX或Prometheus的JMX Exporter来暴露JVM指标。用户之前的问题中也提到了Prometheus的配置,所以可能需要使用这些工具。接下来,步骤可能包括: 1. **在Cassandra Pod中启用JMXExporter**:将JMX Exporter作为sidecar容器添加到Cassandra的Pod中,或者配置Cassandra的JVM参数以通过JMX暴露指标。这需要修改Cassandra的部署配置,添加JMX相关的参数,比如端口和认证信息。2.**配置Prometheus抓取指标**:确保Prometheus能够发现Cassandra的Pod,并正确配置ServiceMonitor或PodMonitor来抓取JMX Exporter暴露的指标。引用[2]中提到Prometheus的配置和重启,这可能相关。 3. **验证指标是否可用**:在Prometheus中查询cass_jvm_heap和cass_jvm_heap_max是否存在,并确保数据正确。引用[2]中的步骤可以用于验证目标是否UP,并查看图表数据。4.**Grafana展示**:创建仪表盘展示这些指标,可能需要根据JVM的内存模型(引用[3])来设计图表,比如堆内存的使用量和最大值的关系。 需要注意的细节:- Cassandra的JVM参数可能需要调整,以允许远程JMX连接,或者使用JMXExporter的agent模式。例如,启动时添加-javaagent参数指向JMX Exporter的jar包,并指定配置文件。- Kubernetes的服务发现需要正确设置,特别是如果Cassandra部署在StatefulSet中,可能需要特定的标签或注解让Prometheus识别。-安全方面,JMX通常需要认证,可能需要配置Secrets来存储用户名和密码,或者在JMX Exporter的配置中禁用安全措施(不推荐生产环境)。- JVM堆内存的指标名称可能因JMX Exporter的配置而不同,需要确认实际的指标名称是否为cass_jvm_heap和cass_jvm_heap_max,或者是否有不同的命名规则。可能的挑战: -用户是否已经部署了Prometheus和Grafana?如果没有,可能需要先部署这些监控组件。- Cassandra的版本是否支持所需的JMX配置?引用[1]提到特定版本的Cassandra的memtable配置,这可能影响JMX的可用性。-是否需要考虑Cassandra集群的多个节点,每个节点的JVM指标都需要监控? 结合这些思考,解决方案的步骤可能包括配置JMX Exporter、更新Prometheus配置、验证指标,最后在Grafana中展示。同时,需要引用之前的引用内容,例如引用[3]中的JVM内存模型来指导监控哪些指标,引用[2]的Prometheus配置步骤。</think>### 在 Kubernetes 中监控 Cassandra JVM 堆内存和最大堆内存的步骤 #### 1. **为 Cassandra 暴露 JVM 指标** Cassandra 的 JVM 指标可通过 JMX 或 Prometheus JMX Exporter 暴露。以下是两种方法: - **方法一:使用 JMX Exporter(推荐)** 1. **添加 JMX Exporter 作为 Sidecar 容器** 修改 Cassandra 的 Pod 配置,添加 JMX Exporter 容器: ```yaml containers: - name: cassandra image: cassandra:latest # 原 Cassandra 配置保持不变 - name: jmx-exporter image: bitnami/jmx-exporter:latest ports: - containerPort: 9404 command: - java - -jar - jmx_prometheus_httpserver.jar - "9404" - /config/config.yaml volumeMounts: - name: jmx-config mountPath: /config volumes: - name: jmx-config configMap: name: jmx-exporter-config ``` 2. **创建 JMX Exporter 配置文件** 生成 `jmx-exporter-config.yaml`,定义要采集的 JVM 指标(如堆内存): ```yaml lowercaseOutputName: true rules: - pattern: "java.lang:type=MemoryPool,name=.*" name: cass_jvm_heap_$1 labels: pool: "$1" - pattern: "java.lang:type=Memory" name: cass_jvm_heap_max labels: type: "heap" ``` 通过 ConfigMap 挂载到容器: ```bash kubectl create configmap jmx-exporter-config --from-file=config.yaml=jmx-exporter-config.yaml ``` - **方法二:直接启用 JMX 端口** 在 Cassandra 的 JVM 参数中启用 JMX 远程访问: ```yaml env: - name: JVM_EXTRA_OPTS value: "-Dcom.sun.management.jmxremote -Dcom.sun.management.jmxremote.port=7199 -Dcom.sun.management.jmxremote.authenticate=false -Dcom.sun.management.jmxremote.ssl=false" ``` --- #### 2. **配置 Prometheus 抓取指标** 确保 Prometheus 能发现 Cassandra Pod 的指标端点: - **通过 ServiceMonitor 配置**(需安装 Prometheus Operator) ```yaml apiVersion: monitoring.coreos.com/v1 kind: ServiceMonitor metadata: name: cassandra-monitor namespace: monitoring spec: endpoints: - port: jmx-metrics # 对应 JMX Exporter 的端口名称 interval: 15s selector: matchLabels: app: cassandra # 匹配 Cassandra Pod 的标签 ``` - **通过静态配置**(传统 Prometheus 配置) 在 `prometheus.yml` 中添加: ```yaml scrape_configs: - job_name: &#39;cassandra-jvm&#39; static_configs: - targets: [&#39;cassandra-service:9404&#39;] # JMX Exporter 的服务地址 ``` 重启 Prometheus 容器使配置生效[^2]。 --- #### 3. **验证指标采集** 1. **检查 Prometheus 目标状态** 访问 `http://<prometheus-ip>:9090/targets`,确认对应 Target 状态为 **UP**[^2]。 2. **查询指标** 在 Prometheus 中执行以下查询: ```promql cass_jvm_heap_used{pool="PS Eden Space"} # Eden 区内存使用量 cass_jvm_heap_max{type="heap"} # 最大堆内存 ``` --- #### 4. **在 Grafana 中可视化** 1. **导入 JVM 监控仪表盘** 使用官方或自定义的 JVM 仪表盘模板(如 ID 8563),配置数据源为 Prometheus。 2. **自定义图表** 添加面板展示 `cass_jvm_heap_used` 和 `cass_jvm_heap_max`: ```promql sum(cass_jvm_heap_used) by (pod) # 当前堆内存使用量 sum(cass_jvm_heap_max) by (pod) # 最大堆内存配置 ``` 结合 JVM 内存模型(堆、Eden、Survivor 区)设计图表[^3]。 --- ### 关键公式与单位 - **堆内存使用率计算公式**: $$ \text{Heap Usage Rate} = \frac{\text{cass\_jvm\_heap\_used}}{\text{cass\_jvm\_heap\_max}} \times 100\% $$ - **单位转换**: $$ 1 \text{GB} = 1073741824 \text{ bytes} $$ --- ### 相关问题 1. 如何通过 Kubernetes Horizontal Pod Autoscaler (HPA) 基于 JVM 堆内存自动扩展 Cassandra Pod? 2. Cassandra JVM 堆内存溢出(OOM)的常见原因及排查方法? 3. 如何优化 Prometheus 对高频 JVM 指标的采集性能? 4. 在 Kubernetes 中如何动态调整 JVM 堆内存参数(如 `-Xmx`)? --- 通过上述步骤,可实现对 Cassandra JVM 堆内存的实时监控。若指标未显示,需检查 JMX Exporter 配置、网络策略及 Prometheus 服务发现机制[^2][^3]。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值