JVM学习三

Java类加载机制与字节码详解
本文深入探讨Java类文件结构,包括魔数、版本、常量池等元素,解析javap工具如何反编译class文件揭示字节码信息。详述类加载过程,包括加载、链接和初始化阶段,以及类加载器的工作原理和双亲委派模式。理解Java运行时类加载的细节。

1.类文件结构

通常一个java文件,编译之后会变成字节码文件。根据jvm规范,类文件的结构如下:

classFile{
    u4 magic; #魔数,表示其是否是类文件,0-3字节,ca fe ba be
    u2 minor_version; #版本,4-7字节,表示类的版本,其中34表示java8,52表示java9
    u2 major_version; #主版本,
    u2 constant_pool_count; #常量池,8-9字节,常量池长度
    #常量池信息    
    cp_info constant_pool[constant_pool_count-1];
    u2 access_flags;#访问标记,通常public、private、protect
    u2 this_class; #类信息
    u2 super_class; #父类信息
    u2 interfaces_count;#接口信息
    u2 interfaces[interfaces_count];
    u2 fields_count;#字段信息,成员变量信息
    field_info fileds[fields_count];
    u2 methodsCount;#方法信息
    method_info methods[methoos_count];
    u2 attributes_count;#属性信息
    attribute_info attributes[attributes_count];
}

2.编译javap

通过javap工具,我么可以反编译class文件,从而看到java的字节码信息:

javap -v xxx.class

从字节码文件中,我们可以看到类的文件的相关信息,版本信息、字段、常量池信息、属性信息、方法信息,继承信息和标识信息等。

通常原始java代码,编译后变成字节码文件,常量信息,会放入常量池中,运行时放入到运行时常量池中。而运行常量池类似hash表,在里面可以看到里面的常量的信息。方法字节码载入方法区,main线程开始运行,分配栈帧内存。而栈帧的数据结构是栈,先进后出的特点。接着执行引擎完成字节码操作。

在编译过程期间,会自动生成和转换一些代码,方便运行。

3.类加载阶段

加载

将类的字节码载入方法区中,内部采用C++的instanceKlass描述java类,相关字段:

_java_mirror #java的类镜像,方便java使用
—super #父类
—fields #成员变量
—methods #方法
—constants #常量池
—class_loader #类加载器
—vtable #虚方法表
—itable #接口方法表

如果这个类还有父类没有加载,先加载父类。同时加载和链接可以交替运行的。

链接
链接的过程中,需要进行验证、准备、解析工作。
其中验证时验证类是否符合jvm规范,安全性检查。
准备是为static变量分配空间,设置默认值,
将常量池中的符号引用解析为直接引用。
初始化

() v 方法,初始化即调用() v,虚拟机会保证这个类的构造方法的线程安全。

发生的时机:类的初始化时惰性的。main方法所在的类总会被首先初始化,首次访问这个方法的静态变量或静态方法,子类初始化,如果父类还没有初始化,则会子类访问父类的静态变量,触发父类的初始化。class.forName,new会导致初始化等。

不会触发初始化的情况:

访问static final静态常量、访问类对象的.class、创建该类的数组等。

4.类加载器

Bootstrap ClassLoader:加载java_home的lib信息
Extension ClassLoader:加载java_home中的lib/ext中的信息
Application ClassLoader:加载应用的classpath的信息
自定义类加载器:自定义路径的信息

上面的四种类加载器存在上下级关系。同时从源码里面会看到其涉及双亲委派模式。

双亲委派模式:调用类加载器的loadClass方法时,查找类的规则。

查看此类是否已经加载,有上级的话,委派上级ExtClassLoader的loadClass,如果没有上级,则委派BootstrapClassLoader。如果每一层找不到,则找自定义类加载器加载。

什么时候我们会用到自定义类加载器:

1.想加载非classpath随意路径中的类文件
2.都是通过接口来使用实现,希望解耦时,常用在框架设计
3.这些类希望予以隔离,不同应用的同名类都可以加载,
  不冲突,常见于tomcat容器中

双亲委派模式保证了类的唯一性和安全性。也就是说如果包含相同类包下和相同类名的两个类,它是无法加载的。
在tomcat和OSGI中,是不在准守双亲委派机制的。我们知道Tomcat可以加载多个war包,同时可以启动运行的,此时加载的系统类加载器和扩展类加载器是一样的,同时实现了自己的类加载器,在tomcat的WEB-INF中,可以看到CommonClassLoader、CatalinaClassLoader、SharedClassLoader、WebappClassLoader,而CommonClassLoader是CatalinaClassLoader、SharedClassLoader的公共库,可以被它们俩调用,但是两者之间又是隔离的。同时SharedClassLoader可以被WebappClassLoader调用。而WebappClassLoader之间又是隔离的。而CommonClassLoader想要调用WebappClassLoader,则采用线程上下文类加载器可以实现,使用线程上下文类加载器,可以让父类加载器请求子类加载器去完成类加载的动作。

### 如何使用 `kubectl logs` 查看 Kubernetes Pod 的日志 要查看 Kubernetes 中某个 Pod 的日志,可以通过 `kubectl logs` 命令实现。以下是关于该命令的一些常见用法及其功能: #### 1. 查看单个 Pod 的日志 如果只想查看特定 Pod 的日志,可以直接运行以下命令: ```bash kubectl logs <pod-name> ``` 这会返回指定 Pod 当前容器的标准输出日志[^1]。 #### 2. 实时刷新日志 为了持续跟踪日志的变化,可以加上 `-f` 参数来实现实时更新: ```bash kubectl logs -f <pod-name> [-n <namespace>] ``` 此参数的作用类似于 Linux 下的 `tail -f` 命令,能够动态展示最新的日志内容[^3]。 #### 3. 显示最近的日志条目 有时只需要关注最新的一部分日志而不是全部历史记录,这时可以用 `--tail` 参数限定显示的日志行数: ```bash kubectl logs --tail=<number-of-lines> <pod-name> [-n <namespace>] ``` 例如,仅显示最后 200 行日志: ```bash kubectl logs --tail=200 <pod-name> [-n <namespace>] ``` 上述方法适用于快速定位问题或减少不必要的数据量。 #### 4. 过滤时间范围内的日志 当需要查找某段时间内发生的事件时,可通过 `--since` 参数筛选出这段时间的日志: ```bash kubectl logs --since=<time-period> <pod-name> [-n <namespace>] ``` 比如获取过去两小时的日志: ```bash kubectl logs --since=2h <pod-name> [-n <namespace>] ``` 这种方法特别适合排查近期发生的问题。 #### 5. 使用自定义 kubeconfig 文件 如果有多个集群环境,则可能需要用到不同的 kubeconfig 文件连接到相应的 K8S 集群。此时可以在命令中加入 `--kubeconfig` 参数指定路径: ```bash kubectl --kubeconfig="<path-to-kubeconfig>" logs -f <pod-name> [-n <namespace>] ``` 这样就可以灵活切换不同配置下的资源管理操作。 #### 注意事项 尽管 `kubectl logs` 是一种非常方便的方式用于访问容器内部产生的信息流,但在某些情况下可能会遇到无法正常读取的情况。这些障碍通常涉及权限设置错误、节点离线或者目标 pod 已经终止等问题。因此,在实际应用过程中应当仔细检查每一个环节是否存在潜在隐患并采取相应措施加以解决[^4]。 --- ### 示例代码 假设有一个名为 `my-pod` 的 Pod 处于默认命名空间下,下面是一些具体的例子演示如何调用相关选项: ```bash # 获取 my-pod 的所有日志 kubectl logs my-pod # 动态监控 my-pod 的日志变化 kubectl logs -f my-pod # 只查看 my-pod 最近 100 条日志记录 kubectl logs --tail=100 my-pod # 提取 my-pod 在过去的半小时所产生的日志 kubectl logs --since=30m my-pod ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值