jvm源码解读--08 创建oop对象,将static静态变量放置在oop的96 offset处
之前分析的已经加载的.Class文件中都没有Static 静态变量,所以也就没这部分的解析,自己也是不懂hotspot 将静态变量放哪里去了,追踪源码之后,看清楚了整个套路,总体上来说,可以举例来说对于,java.lang.String的Class文件进行解析,String类有5个变量,其中有俩个静态变量
private final char value[]; private int hash; // Default to 0
private static final long serialVersionUID = -6849794470754667710L;
private static final ObjectStreamField[] serialPersistentFields =
new ObjectStreamField[0];
public static final Comparator<String> CASE_INSENSITIVE_ORDER
= new CaseInsensitiveComparator();
private static class CaseInsensitiveComparator
implements Comparator<String>, java.io.Serializable {
// use serialVersionUID from JDK 1.2.2 for interoperability
private static final long serialVersionUID = 8575799808933029326L; public int compare(String s1, String s2) {
int n1 = s1.length();
int n2 = s2.length();
int min = Math.min(n1, n2);
for (int i = 0; i < min; i++) {
char c1 = s1.charAt(i);
char c2 = s2.charAt(i);
if (c1 != c2) {
c1 = Character.toUpperCase(c1);
c2 = Character.toUpperCase(c2);
if (c1 != c2) {
c1 = Character.toLowerCase(c1);
c2 = Character.toLowerCase(c2);
if (c1 != c2) {
// No overflow because of numeric promotion
return c1 - c2;
}
}
}
}
return n1 - n2;
} /** Replaces the de-serialized object. */
private Object readResolve() { return CASE_INSENSITIVE_ORDER; }
}
看到了有5个成员变量
private final char value[];
private int hash;
private static final long serialVersionUID = -6849794470754667710L;
private static final ObjectStreamField[] serialPersistentFields =
new ObjectStreamField[0];
public static final Comparator<String> CASE_INSENSITIVE_ORDER
= new CaseInsensitiveComparator();
第5个是一个内部类
private static class CaseInsensitiveComparator
先补充好,常量池的解析Field这部分知识
先看jvm规范对于field的定义
The structure has the following format:
field_info {
u2 access_flags;
u2 name_index;
u2 descriptor_index;
u2 attributes_count;
attribute_info attributes[attributes_count];
}
Table 4.5-A. Field access and property flags
Flag Name Value Interpretation |
ACC_PUBLIC 0x0001 Declared public; may be accessed from outside itspackage. |
ACC_PRIVATE 0x0002 Declared private; usable only within the definingclass. |
ACC_PROTECTED 0x0004 Declared protected; may be accessed withinsubclasses. |
ACC_STATIC 0x0008 Declared static. |
ACC_FINAL 0x0010 Declared final; never directly assigned to afterobject construction (JLS §17.5). |
ACC_VOLATILE 0x0040 Declared volatile; cannot be cached. |
ACC_TRANSIENT 0x0080 Declared transient; not written or read by apersistent object manager. |
ACC_SYNTHETIC 0x1000 Declared synthetic; not present in the source code. |
ACC_ENUM 0x4000 Declared as an element of an enum. |
对这四部分进行说明
access_flags
- 说明,这个是变量的访问标识符,包含了,public private static ,final,voliat等,已经组合
name_index
便是变量的名字,指向常量池
descriptor_index
- 表示变量的类型信息 如int long Object ,ArrayType 等,下边的表中列出来BCDIJLSZ[ 等
attributes_count
属性值
attribute_info attributes[attributes_count];
属性,这里主要介绍 ConstantValue这个属性
Table 4.3-A. Interpretation of field descriptors
FieldType term Type Interpretation |
B byte signed byte |
C char Unicode character code point in the Basic Multilingual Plane, encoded with UTF-16 |
D double double-precision floating-point value |
F float single-precision floating-point value |
I int integer |
J long long integer |
L ClassName ; reference an instance of class ClassName |
S short signed short |
Z boolean true or false |
[ reference one array dimension |
ConstantValue这个属性
The ConstantValue attribute has the following format:
ConstantValue_attribute {
u2 attribute_name_index;
u4 attribute_length;
u2 constantvalue_index;
}
The items of the ConstantValue_attribute structure are as follows:
attribute_name_index
The value of the attribute_name_index item must be a valid index into the constant_pool table. The constant_pool entry at that index
must be a CONSTANT_Utf8_info structure (§4.4.7) representing the string"ConstantValue".
attribute_length
The value of the attribute_length item of a ConstantValue_attribute structure must be two.
constantvalue_index
The value of the constantvalue_index item must be a valid index intothe constant_pool table. The constant_pool entry at that index gives the
constant value represented by this attribute. The constant_pool entry must beof a type appropriate to the field, as specified in Table 4.7.2-A.
Table 4.7.2-A. Constant value attribute types
Field Type Entry Type |
long CONSTANT_Long |
float CONSTANT_Float |
double CONSTANT_Double |
int, short, char, byte, boolean CONSTANT_Integer |
String CONSTANT_String |
说的很清楚了,这个值需要是上述表格的中的类型
那就拿一个例子出来
这个field 共有5个,这个是第三个.
那么分析:
- access_flags 是private static final
- 属性名字叫serialVersionUID,156是是常量池的索引
- descriptor_index 是J 那么解析出来就是LONG类型
- 有一个ConatantValue的属性
- 158 就是 ConatantValue
- attribte_length 必须是2
- 值的索引指向159,可以看到159是LONG类型的负数
那么hotspot中如何解析的呢?
在classFileParse.cpp中 u2 java_fields_count = 0;
// Fields (offsets are filled in later)
FieldAllocationCount fac;
Array<u2>* fields = parse_fields(class_name,
access_flags.is_interface(),
&fac, &java_fields_count,
CHECK_(nullHandle));
这里就不粘贴源码了,附带参考书中的解释
这就清晰的过程,最后得到_short变得就是以下结构
$49 = {26, 156, 157, 159, 33, 0}
class FieldInfo VALUE_OBJ_CLASS_SPEC { enum FieldOffset {
access_flags_offset = 0,
name_index_offset = 1,
signature_index_offset = 2,
initval_index_offset = 3,
low_packed_offset = 4,
high_packed_offset = 5,
field_slots = 6
}; private:
u2 _shorts[field_slots];
}
解析的变量信息,那就解析一下子
Array<u2>* ClassFileParser::parse_fields(Symbol* class_name,
bool is_interface,
FieldAllocationCount *fac,
u2* java_fields_count_ptr, TRAPS) {
ClassFileStream* cfs = stream();
cfs->guarantee_more(2, CHECK_NULL); // length
u2 length = cfs->get_u2_fast();
*java_fields_count_ptr = length; int num_injected = 0;
InjectedField* injected = JavaClasses::get_injected(class_name, &num_injected);
int total_fields = length + num_injected; // The field array starts with tuples of shorts 说明field array 由 shorts类型的元组组成,每个分别是
// [access, name index, sig index, initial value index, byte offset].
// A generic signature slot only exists for field with generic
// signature attribute. And the access flag is set with
// JVM_ACC_FIELD_HAS_GENERIC_SIGNATURE for that field. The generic
// signature slots are at the end of the field array and after all
// other fields data.
//
// f1: [access, name index, sig index, initial value index, low_offset, high_offset]
// f2: [access, name index, sig index, initial value index, low_offset, high_offset]
// ...
// fn: [access, name index, sig index, initial value index, low_offset, high_offset]
// [generic signature index]
// [generic signature index]
// ...
//
// Allocate a temporary resource array for field data. For each field,
// a slot is reserved in the temporary array for the generic signature
// index. After parsing all fields, the data are copied to a permanent
// array and any unused slots will be discarded.
ResourceMark rm(THREAD);
u2* fa = NEW_RESOURCE_ARRAY_IN_THREAD(
THREAD, u2, total_fields * (FieldInfo::field_slots + 1)); // The generic signature slots start after all other fields' data.
int generic_signature_slot = total_fields * FieldInfo::field_slots;
int num_generic_signature = 0;
for (int n = 0; n < length; n++) {
cfs->guarantee_more(8, CHECK_NULL); // access_flags, name_index, descriptor_index, attributes_count AccessFlags access_flags;
jint flags = cfs->get_u2_fast() & JVM_RECOGNIZED_FIELD_MODIFIERS;
verify_legal_field_modifiers(flags, is_interface, CHECK_NULL);
access_flags.set_flags(flags); u2 name_index = cfs->get_u2_fast();
int cp_size = _cp->length();
check_property(valid_symbol_at(name_index),
"Invalid constant pool index %u for field name in class file %s",
name_index,
CHECK_NULL);
Symbol* name = _cp->symbol_at(name_index);
verify_legal_field_name(name, CHECK_NULL); u2 signature_index = cfs->get_u2_fast();
check_property(valid_symbol_at(signature_index),
"Invalid constant pool index %u for field signature in class file %s",
signature_index, CHECK_NULL);
Symbol* sig = _cp->symbol_at(signature_index);
verify_legal_field_signature(name, sig, CHECK_NULL); u2 constantvalue_index = 0;
bool is_synthetic = false;
u2 generic_signature_index = 0;
bool is_static = access_flags.is_static();
FieldAnnotationCollector parsed_annotations(_loader_data); u2 attributes_count = cfs->get_u2_fast();
if (attributes_count > 0) {
parse_field_attributes(attributes_count, is_static, signature_index,
&constantvalue_index, &is_synthetic,
&generic_signature_index, &parsed_annotations,
CHECK_NULL);
if (parsed_annotations.field_annotations() != NULL) {
if (_fields_annotations == NULL) {
_fields_annotations = MetadataFactory::new_array<AnnotationArray*>(
_loader_data, length, NULL,
CHECK_NULL);
}
_fields_annotations->at_put(n, parsed_annotations.field_annotations());
parsed_annotations.set_field_annotations(NULL);
}
if (parsed_annotations.field_type_annotations() != NULL) {
if (_fields_type_annotations == NULL) {
_fields_type_annotations = MetadataFactory::new_array<AnnotationArray*>(
_loader_data, length, NULL,
CHECK_NULL);
}
_fields_type_annotations->at_put(n, parsed_annotations.field_type_annotations());
parsed_annotations.set_field_type_annotations(NULL);
} if (is_synthetic) {
access_flags.set_is_synthetic();
}
if (generic_signature_index != 0) {
access_flags.set_field_has_generic_signature();
fa[generic_signature_slot] = generic_signature_index;
generic_signature_slot ++;
num_generic_signature ++;
}
} FieldInfo* field = FieldInfo::from_field_array(fa, n);
field->initialize(access_flags.as_short(),
name_index,
signature_index,
constantvalue_index);
那么进入 field->initialize
void initialize(u2 access_flags,
u2 name_index,
u2 signature_index,
u2 initval_index) {
_shorts[access_flags_offset] = access_flags;
_shorts[name_index_offset] = name_index;
_shorts[signature_index_offset] = signature_index;
_shorts[initval_index_offset] = initval_index;
_shorts[low_packed_offset] = 0;
_shorts[high_packed_offset] = 0;
}
上述就是,看initval_index这个就是初始值,就是默认值
最终的field其实是这个东西
(gdb) p _shorts
$20 = {18, 152, 153, 0, 0, 0}
BasicType type = _cp->basic_type_for_signature_at(signature_index);
获取变量值
转换
// Convert a char from a classfile signature to a BasicType
inline BasicType char2type(char c) {
switch( c ) {
case 'B': return T_BYTE;
case 'C': return T_CHAR;
case 'D': return T_DOUBLE;
case 'F': return T_FLOAT;
case 'I': return T_INT;
case 'J': return T_LONG;
case 'S': return T_SHORT;
case 'Z': return T_BOOLEAN;
case 'V': return T_VOID;
case 'L': return T_OBJECT;
case '[': return T_ARRAY;
}
return T_ILLEGAL;
}
计算每种类型的变量总量
// Remember how many oops we encountered and compute allocation type
FieldAllocationType atype = fac->update(is_static, type); FieldAllocationType update(bool is_static, BasicType type) {
FieldAllocationType atype = basic_type_to_atype(is_static, type);
// Make sure there is no overflow with injected fields.
assert(count[atype] < 0xFFFF, "More than 65535 fields");
count[atype]++;
return atype;
}
查看
(gdb) p atype
$21 = NONSTATIC_OOP
void set_allocation_type(int type) { //type=5
u2 lo = _shorts[low_packed_offset];
switch(lo & FIELDINFO_TAG_MASK) {
case FIELDINFO_TAG_BLANK:
_shorts[low_packed_offset] = ((type << FIELDINFO_TAG_SIZE)) & 0xFFFF;
_shorts[low_packed_offset] &= ~FIELDINFO_TAG_MASK;
_shorts[low_packed_offset] |= FIELDINFO_TAG_TYPE_PLAIN;
return; }
(gdb) p _shorts
$22 = {18, 152, 153, 0, 22, 0}
看出来将第5位置设置为0到22 即为0x16
那么
// Packed field has the tag, and can be either of:
// hi bits <--------------------------- lo bits
// |---------high---------|---------low---------|
// ..........................................00 - blank
// [------------------offset----------------]01 - real field offset
// ......................[-------type-------]10 - plain field with type
// [--contention_group--][-------type-------]11 - contended field with type and contention group
二进制为10110 那么这个就解析为 plain field with type, 这个5 就是
(gdb) p atype
$21 = NONSTATIC_OOP
enum FieldAllocationType {
STATIC_OOP, // Oops
STATIC_BYTE, // Boolean, Byte, char
STATIC_SHORT, // shorts
STATIC_WORD, // ints
STATIC_DOUBLE, // aligned long or double
NONSTATIC_OOP,
NONSTATIC_BYTE,
NONSTATIC_SHORT,
NONSTATIC_WORD,
NONSTATIC_DOUBLE,
MAX_FIELD_ALLOCATION_TYPE,
BAD_ALLOCATION_TYPE = -1
};
这就存在一个转换过程
FieldAllocationType atype = fac->update(is_static, type); FieldAllocationType update(bool is_static, BasicType type) {
FieldAllocationType atype = basic_type_to_atype(is_static, type);
// Make sure there is no overflow with injected fields.
assert(count[atype] < 0xFFFF, "More than 65535 fields");
count[atype]++;
return atype;
} static FieldAllocationType basic_type_to_atype(bool is_static, BasicType type) {
assert(type >= T_BOOLEAN && type < T_VOID, "only allowable values");
FieldAllocationType result = _basic_type_to_atype[type + (is_static ? (T_CONFLICT + 1) : 0)];
assert(result != BAD_ALLOCATION_TYPE, "bad type");
return result;
} static FieldAllocationType _basic_type_to_atype[2 * (T_CONFLICT + 1)] = {
BAD_ALLOCATION_TYPE, // 0
BAD_ALLOCATION_TYPE, // 1
BAD_ALLOCATION_TYPE, // 2
BAD_ALLOCATION_TYPE, // 3
NONSTATIC_BYTE , // T_BOOLEAN = 4,
NONSTATIC_SHORT, // T_CHAR = 5,
NONSTATIC_WORD, // T_FLOAT = 6,
NONSTATIC_DOUBLE, // T_DOUBLE = 7,
NONSTATIC_BYTE, // T_BYTE = 8,
NONSTATIC_SHORT, // T_SHORT = 9,
NONSTATIC_WORD, // T_INT = 10,
NONSTATIC_DOUBLE, // T_LONG = 11,
NONSTATIC_OOP, // T_OBJECT = 12,
NONSTATIC_OOP, // T_ARRAY = 13,
BAD_ALLOCATION_TYPE, // T_VOID = 14,
BAD_ALLOCATION_TYPE, // T_ADDRESS = 15,
BAD_ALLOCATION_TYPE, // T_NARROWOOP = 16,
BAD_ALLOCATION_TYPE, // T_METADATA = 17,
BAD_ALLOCATION_TYPE, // T_NARROWKLASS = 18,
BAD_ALLOCATION_TYPE, // T_CONFLICT = 19,
BAD_ALLOCATION_TYPE, // 0
BAD_ALLOCATION_TYPE, // 1
BAD_ALLOCATION_TYPE, // 2
BAD_ALLOCATION_TYPE, // 3
STATIC_BYTE , // T_BOOLEAN = 4,
STATIC_SHORT, // T_CHAR = 5,
STATIC_WORD, // T_FLOAT = 6,
STATIC_DOUBLE, // T_DOUBLE = 7,
STATIC_BYTE, // T_BYTE = 8,
STATIC_SHORT, // T_SHORT = 9,
STATIC_WORD, // T_INT = 10,
STATIC_DOUBLE, // T_LONG = 11,
STATIC_OOP, // T_OBJECT = 12,
STATIC_OOP, // T_ARRAY = 13,
BAD_ALLOCATION_TYPE, // T_VOID = 14,
BAD_ALLOCATION_TYPE, // T_ADDRESS = 15,
BAD_ALLOCATION_TYPE, // T_NARROWOOP = 16,
BAD_ALLOCATION_TYPE, // T_METADATA = 17,
BAD_ALLOCATION_TYPE, // T_NARROWKLASS = 18,
BAD_ALLOCATION_TYPE, // T_CONFLICT = 19,
};
完成了第一个变量的解析,现在执行到第三变量的解析 serialVersionUID ,他比前两个多了一个常数属性,那么主要看这个常数的解析
if (attributes_count > 0) {
parse_field_attributes(attributes_count, is_static, signature_index,
&constantvalue_index, &is_synthetic,
&generic_signature_index, &parsed_annotations,
CHECK_NULL);
...}
再看
//主干
void ClassFileParser::parse_field_attributes(u2 attributes_count,
bool is_static, u2 signature_index,
u2* constantvalue_index_addr,
bool* is_synthetic_addr,
u2* generic_signature_index_addr,
ClassFileParser::FieldAnnotationCollector* parsed_annotations,
TRAPS) { ...
*constantvalue_index_addr = constantvalue_index;
*is_synthetic_addr = is_synthetic;
*generic_signature_index_addr = generic_signature_index;
..}
接着就是初始化field变量
FieldInfo* field = FieldInfo::from_field_array(fa, n);
field->initialize(access_flags.as_short(),
name_index,
signature_index,
constantvalue_index);
标记的是将常数给赋值了的操作
今天先到这里,具体的解析在oop中的存储明天在说了
jvm源码解读--08 创建oop对象,将static静态变量放置在oop的96 offset处的更多相关文章
- jvm源码解读--09 创建oop对象,将static静态变量放置在oop的96 offset处 第二篇
先打断点systemDictionary.cpp 1915行 Universe::fixup_mirrors(CHECK); 进入 void Universe::fixup_mirrors(TRAPS ...
- jvm源码解读--07 创建 fixup_mirrors
通过前面的分析,创建的insttanceKlass 都没放入了java_lang_Class::fixup_mirror_list()这里类的数组里面了,所有的instance列举如下 ------- ...
- JVM 源码解读之 CMS 何时会进行 Full GC
t点击上方"涤生的博客",关注我 转载请注明原创出处,谢谢!如果读完觉得有收获的话,欢迎点赞加关注. 前言 本文内容是基于 JDK 8 在文章 JVM 源码解读之 CMS GC 触 ...
- jvm源码解读--17 Java的wait()、notify()学习
write and debug by 张艳涛 wait()和notify()的通常用法 A线程取得锁,执行wait(),释放锁; B线程取得锁,完成业务后执行notify(),再释放锁; B线程释放锁 ...
- jvm源码解读--15 oop对象详解
(gdb) p obj $15 = (oopDesc *) 0xf3885d08 (gdb) p * obj $16 = { _mark = 0x70dea4e01, _metadata = { _k ...
- jvm源码解读--13 gc_root中的栈中oop的mark 和copy 过程分析
粘贴源码 package com.test; import java.util.Random; public class Test { static int number=12; private in ...
- jvm源码解读--11 ldc指令的解读
写一个java文件 public static void main(String[] args) { String str1="abc"; String str2 ="a ...
- jvm源码解读--12 invokspecial指令的解读
先看代码 package com.zyt.jvmbook; public class Girl extends Person{ public Girl() { int a; } @Override p ...
- jvm源码解读--06 Method 方法解析
进入 // Methods bool has_final_method = false; AccessFlags promoted_flags; promoted_flags.set_flags(0) ...
随机推荐
- Django基础之自定义分页器
自定义分页器 针对批量插入的数据,我们在前端展示的时候发现一个很严重的问题,一页展示了所有的数据,数据量太大,查看不方便 针对数据量大但又需要全部展示给用户观看的情况下,我们统一做法都是做分页处理 分 ...
- Java持久层框架Mybatis入门
MyBatis是什么 MyBatis是Java的持久层框架,GitHub的star数高达15.8k,是Java技术栈中最热门的ORM框架之一.它支持自定义SQL.存储过程以及高级映射,可以通过XML或 ...
- .NET Core/.NET5/.NET6 开源项目汇总3:工作流组件
系列目录 [已更新最新开发文章,点击查看详细] 开源项目是众多组织与个人分享的组件或项目,作者付出的心血我们是无法体会的,所以首先大家要心存感激.尊重.请严格遵守每个项目的开源协议后再使用.尊 ...
- 【题解】入阵曲 luogu3941 前缀和 压维
丹青千秋酿,一醉解愁肠. 无悔少年枉,只愿壮志狂 题目 题目描述 小 F 很喜欢数学,但是到了高中以后数学总是考不好. 有一天,他在数学课上发起了呆:他想起了过去的一年.一年前,当他初识算法竞赛的 时 ...
- Unity3D学习笔记1——绘制一个三角形
目录 1. 绪论 2. 概述 3. 详论 3.1. 准备 3.2. 实现 3.3. 解析 3.3.1. 场景树对象 3.3.2. 绘制方法 4. 结果 1. 绪论 最近想学习一下Unity3d,无奈发 ...
- text-decoration属性作用和方法
text-decoration-line(注释文本添加一条装饰线):none(文本中没有线条). underline(文本的下方显示一条线). overline(文本的上方将显示一条线). line- ...
- Windows下安装kubectl及Node和Pod操作常用命令
kubernetes通过kube-apiserver作为整个集群管理的入口.Apiserver是整个集群的主管理节点,用户通过Apiserver配置和组织集群,同时集群中各个节点同etcd存储的交互也 ...
- 49、django工程(cookie+session)
49.1.介绍: 1.cookie不属于http协议范围,由于http协议无法保持状态,但实际情况,我们却又需要"保持状态",因此cookie就是在这样一个场景下诞生. cooki ...
- CosId 1.1.8 发布,通用、灵活、高性能的分布式 ID 生成器
CosId 通用.灵活.高性能的分布式 ID 生成器 介绍 CosId 旨在提供通用.灵活.高性能的分布式 ID 生成器. 目前提供了三类 ID 生成器: SnowflakeId : 单机 TPS 性 ...
- 自然语言处理(NLP)——简介
自然语言处理(NLP Natural Language Processing)是一种专业分析人类语言的人工智能.就是在机器语⾔和⼈类语言之间沟通的桥梁,以实现人机交流的目的. 在人工智能出现之前,机器 ...