Field訪問對象int字段,對象訪問int字段,通過openjdk17 C++源碼看對象字段訪問原理

在Java反射機制中,訪問對象的int類型字段值(如field.getInt(object))的底層實現涉及JVM對內存偏移量的計算與直接內存訪問。本文通過分析OpenJDK 17源碼,揭示這一過程的核心實現邏輯。


一、字段偏移量計算

1. Java層初始化偏移量

反射訪問字段時,會通過UnsafeFieldAccessorImpl初始化字段的偏移量:

UnsafeFieldAccessorImpl(Field field) {this.field = field;if (Modifier.isStatic(field.getModifiers()))fieldOffset = unsafe.staticFieldOffset(field);elsefieldOffset = unsafe.objectFieldOffset(field); // 實例字段偏移量isFinal = Modifier.isFinal(field.getModifiers());
}
  • 對于實例字段,調用Unsafe.objectFieldOffset(field)獲取偏移量。

2. 本地方法調用

objectFieldOffset方法通過JNI調用C++實現:

public long objectFieldOffset(Field f) {return objectFieldOffset0(f); // 調用native方法
}
private native long objectFieldOffset0(Field f);
3. C++層計算偏移量

在JVM中,Unsafe_ObjectFieldOffset0最終調用find_field_offset函數:

UNSAFE_ENTRY(jlong, Unsafe_ObjectFieldOffset0(...)) {return find_field_offset(field, 0, THREAD);
} UNSAFE_ENDstatic jlong find_field_offset(...) {oop reflected = JNIHandles::resolve_non_null(field);Klass* k = java_lang_Class::as_Klass(mirror);int slot = java_lang_reflect_Field::slot(reflected); // 獲取字段slotint offset = InstanceKlass::cast(k)->field_offset(slot); // 通過slot計算偏移量return field_offset_from_byte_offset(offset);
}
  • 字段slot:反射對象Field中存儲的slot值對應類元數據(InstanceKlass)中字段的索引。

  • 偏移量計算InstanceKlass::field_offset(slot)通過slot索引從類元數據中獲取字段的實際內存偏移量。


二、通過偏移量訪問字段值

1. Java層讀取字段值

反射調用getInt時,直接通過偏移量訪問內存:

public int getInt(Object obj) {ensureObj(obj);return unsafe.getInt(obj, fieldOffset); // 使用偏移量讀取int值
}
2. C++層內存訪問

在JVM解釋執行字節碼時(如GETFIELD),訪問字段的邏輯與反射一致:

// 字節碼解釋執行邏輯片段
case itos:SET_STACK_INT(obj->int_field(field_offset), -1);break;
  • obj->int_field(field_offset):通過偏移量直接從對象內存中讀取int值。

  • SET_STACK_INT將值壓入操作數棧。


三、關鍵數據結構與內存布局

1. 對象內存布局(oopDesc)

Java對象在內存中的布局包含對象頭(Header)和實例數據(Instance Data):

  • 對象頭:存儲Mark Word和類指針(Klass*)。

  • 實例數據:字段按聲明順序排列,每個字段的偏移量由類元數據確定。

2. 類元數據(Klass)

InstanceKlass存儲類的元信息,包括字段表:

class InstanceKlass : public Klass {// 字段表(fieldDescriptor數組)int field_offset(int slot) const {return field(slot)->offset(); // 獲取字段偏移量}
};
3. 反射字段的slot映射

反射對象Field通過slot與類元數據關聯:

// 反射Field對象存儲slot值
int java_lang_reflect_Field::slot(oop reflect) {return reflect->int_field(_slot_offset);
}
  • slot值在類加載階段生成,對應字段在類字段表中的索引。


四、性能優化與安全性

1. 偏移量緩存

反射調用Field.getInt()時,偏移量(fieldOffset)在UnsafeFieldAccessorImpl初始化階段計算并緩存,后續訪問無需重復計算。

2. 內存直接訪問

通過Unsafe.getInt(obj, offset)繞過Java訪問控制,直接操作內存。這種設計雖然高效,但也繞過了語言層面的安全性檢查。

3. final字段處理

若字段為finalUnsafeFieldAccessorImpl會標記isFinal,部分JVM實現可能阻止修改(盡管某些場景下仍可通過反射修改)。


五、總結

通過反射訪問int字段的流程可概括為:

  1. 計算偏移量:反射初始化階段通過slot從類元數據獲取字段偏移量。

  2. 內存訪問:調用Unsafe.getInt()直接讀取對象內存。

  3. 字節碼執行:解釋器/即時編譯器使用相同機制訪問字段。

這一機制體現了JVM反射與字節碼執行在底層實現上的一致性:均依賴預先計算的字段偏移量直接操作內存。理解這一過程有助于優化反射性能,并為分析JVM內存模型提供基礎。

openjdk17源碼

UnsafeFieldAccessorImpl(Field field) {this.field = field;if (Modifier.isStatic(field.getModifiers()))fieldOffset = unsafe.staticFieldOffset(field);elsefieldOffset = unsafe.objectFieldOffset(field);isFinal = Modifier.isFinal(field.getModifiers());}public long objectFieldOffset(Field f) {if (f == null) {throw new NullPointerException();}return objectFieldOffset0(f);}private native long objectFieldOffset0(Field f);public int getInt(Object obj) throws IllegalArgumentException {ensureObj(obj);return unsafe.getInt(obj, fieldOffset);}} else if (type == Integer.TYPE) {return new UnsafeIntegerFieldAccessorImpl(field);}C++代碼
{CC "objectFieldOffset0", CC "(" FLD ")J",           FN_PTR(Unsafe_ObjectFieldOffset0)},UNSAFE_ENTRY(jlong, Unsafe_ObjectFieldOffset0(JNIEnv *env, jobject unsafe, jobject field)) {return find_field_offset(field, 0, THREAD);
} UNSAFE_ENDstatic jlong find_field_offset(jobject field, int must_be_static, TRAPS) {assert(field != NULL, "field must not be NULL");oop reflected   = JNIHandles::resolve_non_null(field);oop mirror      = java_lang_reflect_Field::clazz(reflected);Klass* k        = java_lang_Class::as_Klass(mirror);int slot        = java_lang_reflect_Field::slot(reflected);int modifiers   = java_lang_reflect_Field::modifiers(reflected);if (must_be_static >= 0) {int really_is_static = ((modifiers & JVM_ACC_STATIC) != 0);if (must_be_static != really_is_static) {THROW_0(vmSymbols::java_lang_IllegalArgumentException());}}int offset = InstanceKlass::cast(k)->field_offset(slot);return field_offset_from_byte_offset(offset);
}int     field_offset      (int index) const { return field(index)->offset(); }int java_lang_reflect_Field::slot(oop reflect) {return reflect->int_field(_slot_offset);
}void java_lang_reflect_Field::set_slot(oop reflect, int value) {reflect->int_field_put(_slot_offset, value);
}oop Reflection::new_field(fieldDescriptor* fd, TRAPS) {Symbol*  field_name = fd->name();oop name_oop = StringTable::intern(field_name, CHECK_NULL);Handle name = Handle(THREAD, name_oop);Symbol*  signature  = fd->signature();InstanceKlass* holder = fd->field_holder();Handle type = new_type(signature, holder, CHECK_NULL);Handle rh  = java_lang_reflect_Field::create(CHECK_NULL);java_lang_reflect_Field::set_clazz(rh(), fd->field_holder()->java_mirror());java_lang_reflect_Field::set_slot(rh(), fd->index());inline jint oopDesc::int_field(int offset) const                    { return HeapAccess<>::load_at(as_oop(), offset);  }
inline jint oopDesc::int_field_raw(int offset) const                { return RawAccess<>::load_at(as_oop(), offset);   }
inline void oopDesc::int_field_put(int offset, jint value)          { HeapAccess<>::store_at(as_oop(), offset, value); }case stos:SET_STACK_INT(obj->short_field(field_offset), -1);break;case itos:SET_STACK_INT(obj->int_field(field_offset), -1);#define DEFINE_GETSETOOP(java_type, Type) \\
UNSAFE_ENTRY(java_type, Unsafe_Get##Type(JNIEnv *env, jobject unsafe, jobject obj, jlong offset)) { \return MemoryAccess<java_type>(thread, obj, offset).get(); \
} UNSAFE_END \T get() {if (_obj == NULL) {GuardUnsafeAccess guard(_thread);T ret = RawAccess<>::load(addr());return normalize_for_read(ret);} else {T ret = HeapAccess<>::load_at(_obj, _offset);return normalize_for_read(ret);}}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/78576.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/78576.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/78576.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

Java查詢數據庫表信息導出Word

參考: POI生成Word多級標題格式_poi設置word標題-CSDN博客 1.概述 使用jdbc查詢數據庫把表信息導出為word文檔, 導出為word時需要下載word模板文件。 已實現數據庫: KingbaseES, 實現代碼: 點擊跳轉 2.效果圖 2.1.生成word內容 所有數據庫合并 數據庫不合并 2.2.生成文件…

Qt中的全局函數講解集合(全)

在頭文件<QtGlobal>中包含了Qt的全局函數&#xff0c;現在就這些全局函數一一詳解。 1.qAbs 原型&#xff1a; template <typename T> T qAbs(const T &t)一個用于計算絕對值的函數。它可以用于計算各種數值類型的絕對值&#xff0c;包括整數、浮點數等 示…

AI與IT協同的典型案例

簡介 本篇代碼示例展示了IT從業者如何與AI協同工作&#xff0c;發揮各自優勢。這些案例均來自2025年的最新企業實踐&#xff0c;涵蓋了不同IT崗位的應用場景。 一、GitHub Copilot生成代碼框架 開發工程師AI協作示例&#xff1a;利用GitHub Copilot生成代碼框架&#xff0c;…

三網通電玩城平臺系統結構與源碼工程詳解(二):Node.js 服務端核心邏輯實現

本篇文章將聚焦服務端游戲邏輯實現&#xff0c;以 Node.js Socket.io 作為主要通信與邏輯處理框架&#xff0c;展開用戶登錄驗證、房間分配、子游戲調度與事件廣播機制的剖析&#xff0c;并附上多個核心代碼段。 一、服務端文件結構概覽 /server/├── index.js …

【prompt是什么?有哪些技巧?】

Prompt&#xff08;提示詞&#xff09;是什么&#xff1f; Prompt 是用戶輸入給AI模型&#xff08;如ChatGPT、GPT-4等&#xff09;的指令或問題&#xff0c;用于引導模型生成符合預期的回答。它的質量直接影響AI的輸出效果。 Prompt 的核心技巧 1. 明確目標&#xff08;Clar…

堆和二叉樹--數據結構初階(3)(C/C++)

文章目錄 前言理論部分堆的模擬實現:(這里舉的大根堆)堆的創建二叉樹的遍歷二叉樹的一些其他功能實現 作業部分 前言 這期的話講解的是堆和二叉樹的理論部分和習題部分 理論部分 二叉樹的幾個性質:1.對于任意一個二叉樹&#xff0c;度為0的節點比度為2的節點多一個 2.對于完全…

Dockerfile講解與示例匯總

容器化技術已經成為應用開發和部署的標準方式,而Docker作為其中的佼佼者,以其輕量、高效、可移植的特性,深受開發者和運維人員的喜愛。本文將從實用角度出發,分享各類常用服務的Docker部署腳本與最佳實踐,希望能幫助各位在容器化之路上少走彎路。 無論你是剛接觸Docker的…

在QGraphicsView中精確地以鼠標為錨縮放圖片

在pyqt中以鼠標所在位置為錨點縮放圖片-CSDN博客中的第一個示例中&#xff0c;通過簡單設置&#xff1a; self.setTransformationAnchor(QGraphicsView.AnchorUnderMouse) 使得QGraphicsView具有了以鼠標為錨進行縮放的功能。但是&#xff0c;其內部應當是利用了滾動條的移動來…

制造工廠如何借助電子看板實現高效生產管控

在當今高度競爭的制造業環境中&#xff0c;許多企業正面臨著嚴峻的管理和生產挑戰。首先&#xff0c;管理流程落后&#xff0c;大量工作仍依賴"人治"方式&#xff0c;高層管理者理論知識薄弱且不愿聽取專業意見。其次&#xff0c;生產過程控制能力不足&#xff0c;導…

在 C# .NET 中駕馭 JSON:使用 Newtonsoft.Json 進行解析與 POST 請求實戰

JSON (JavaScript Object Notation) 已經成為現代 Web 應用和服務之間數據交換的通用語言。無論你是開發后端 API、與第三方服務集成&#xff0c;還是處理配置文件&#xff0c;都繞不開 JSON 的解析與生成。在 C# .NET 世界里&#xff0c;處理 JSON 有多種選擇&#xff0c;其中…

Debian10系統安裝,磁盤分區和擴容

1、說明 過程記錄信息有些不全&#xff0c;僅作為參考。如有其它疑問&#xff0c;歡迎留言。 2、ISO下載 地址&#xff1a;debian-10.13.0鏡像地址 3、開始安裝 3.1、選擇圖形界面 3.2、選擇中文語言 3.3、選擇中國區域 3.4、按照提示繼續 3.5、選擇一個網口 3.6、創建管…

1.10軟考系統架構設計師:優秀架構設計師 - 練習題附答案及超詳細解析

優秀架構設計師綜合知識單選題 每道題均附有答案解析&#xff1a; 題目1 衡量優秀系統架構設計師的核心標準不包括以下哪項&#xff1f; A. 技術全面性與底層系統原理理解 B. 能夠獨立完成模塊開發與調試 C. 與利益相關者的高效溝通與協調能力 D. 對業務需求和技術趨勢的戰略…

MPI Code for Ghost Data Exchange in 3D Domain Decomposition with Multi-GPUs

MPI Code for Ghost Data Exchange in 3D Domain Decomposition with Multi-GPUs Here’s a comprehensive MPI code that demonstrates ghost data exchange for a 3D domain decomposition across multiple GPUs. This implementation assumes you’re using CUDA-aware MPI…

計算機考研精煉 計網

第 19 章 計算機網絡體系結構 19.1 基本概念 19.1.1 計算機網絡概述 1.計算機網絡的定義、組成與功能 計算機網絡是一個將分散的、具有獨立功能的計算機系統&#xff0c;通過通信設備與線路連接起來&#xff0c;由功能完善的軟件實現資源共享和信息傳遞的系統。 …

KUKA機器人自動備份設置

在機器人的使用過程中&#xff0c;對機器人做備份不僅能方便查看機器人的項目配置與程序&#xff0c;還能防止機器人項目和程序丟失時進行及時的還原&#xff0c;因此對機器人做備份是很有必要的。 對于KUKA機器人來說&#xff0c;做備份可以通過U盤來操作。也可以在示教器上設…

【wpf】 WPF中實現動態加載圖片瀏覽器(邊滾動邊加載)

WPF中實現動態加載圖片瀏覽器&#xff08;邊滾動邊加載&#xff09; 在做圖片瀏覽器程序時&#xff0c;遇到圖片數量巨大的情況&#xff08;如幾百張、上千張&#xff09;&#xff0c;一次性加載所有圖片會導致界面卡頓甚至程序崩潰。 本文介紹一種 WPF Prism 實現動態分頁加…

Kubernetes》》k8s》》Taint 污點、Toleration容忍度

污點 》》 節點上 容忍度 》》 Pod上 在K8S中&#xff0c;如果Pod能容忍某個節點上的污點&#xff0c;那么Pod就可以調度到該節點。如果不能容忍&#xff0c;那就無法調度到該節點。 污點和容忍度的概念 》》污點等級——>node 》》容忍度 —>pod Equal——>一種是等…

SEO長尾關鍵詞優化核心策略

內容概要 在搜索引擎優化領域&#xff0c;長尾關鍵詞因其精準的流量捕獲能力與較低的競爭強度&#xff0c;已成為提升網站自然流量的核心突破口。本文圍繞長尾關鍵詞優化的全鏈路邏輯&#xff0c;系統拆解從需求洞察到落地執行的五大策略模塊&#xff0c;涵蓋用戶搜索意圖解析…

AWS中國區ICP備案全攻略:流程、注意事項與最佳實踐

導語 在中國大陸地區開展互聯網業務時,所有通過域名提供服務的網站和應用必須完成ICP備案(互聯網內容提供商備案)。對于選擇使用AWS中國區(北京/寧夏區域)資源的用戶,備案流程因云服務商的特殊運營模式而有所不同。本文將詳細解析AWS中國區備案的核心規則、操作步驟及避坑…

計算機視覺——通過 OWL-ViT 實現開放詞匯對象檢測

介紹 傳統的對象檢測模型大多是封閉詞匯類型&#xff0c;只能識別有限的固定類別。增加新的類別需要大量的注釋數據。然而&#xff0c;現實世界中的物體類別幾乎無窮無盡&#xff0c;這就需要能夠檢測未知類別的開放式詞匯類型。對比學習&#xff08;Contrastive Learning&…