คำนำ
บทความนี้ส่วนใหญ่แนะนำเนื้อหาที่เกี่ยวข้องเกี่ยวกับคลาสที่ไม่ปลอดภัยใน Java มันถูกแบ่งปันสำหรับการอ้างอิงและการเรียนรู้ของคุณ ฉันจะไม่พูดด้านล่างมากนัก มาดูการแนะนำรายละเอียดร่วมกันกันเถอะ
1. การแนะนำชั้นเรียนที่ไม่ปลอดภัย
คลาสที่ไม่ปลอดภัยอยู่ภายใต้แพ็คเกจ Sun.misc และไม่ได้อยู่ในมาตรฐาน Java อย่างไรก็ตามห้องสมุดคลาสพื้นฐานของ Java หลายแห่งรวมถึงห้องสมุดการพัฒนาประสิทธิภาพสูงที่ใช้กันอย่างแพร่หลายได้รับการพัฒนาตามคลาสที่ไม่ปลอดภัยเช่น Netty, Hadoop, Kafka ฯลฯ
ไม่ปลอดภัยสามารถใช้เพื่อเข้าถึงทรัพยากรหน่วยความจำของระบบโดยตรงและจัดการอย่างอิสระ ชั้นเรียนที่ไม่ปลอดภัยมีบทบาทอย่างมากในการปรับปรุงประสิทธิภาพการดำเนินงานของ Java และเพิ่มขีดความสามารถในการดำเนินงานพื้นฐานของภาษา Java
ไม่ปลอดภัยถือได้ว่าเป็นแบ็คดอร์ที่เหลืออยู่ใน Java ให้การดำเนินการระดับต่ำเช่นการเข้าถึงหน่วยความจำโดยตรงการกำหนดเวลาเธรด ฯลฯ
ไม่แนะนำไม่ปลอดภัย
นี่คือตัวอย่างของการใช้ความไม่ปลอดภัย
1.1 ยกตัวอย่างชั้นเรียนส่วนตัว
นำเข้า java.lang.reflect.field; นำเข้า Sun.misc.unsafe; คลาสสาธารณะที่ไม่ปลอดภัย {โมฆะคงที่สาธารณะหลัก (สตริง [] args) พ่นข้อยกเว้น {// อินสแตนซ์ฟิลด์ที่ไม่ปลอดภัย f = unsafe.class.getDeclaredField ("theunsafe"); f.setAccessible (จริง); ไม่ปลอดภัย unsafe = (ไม่ปลอดภัย) f.get (null); // อินสแตนซ์ผู้เล่นผู้เล่นผู้เล่น = (ผู้เล่น) unsafe.allocateInstance (player.class); player.setName ("Li Lei"); System.out.println (player.getName ()); }} เครื่องเล่นคลาส {ชื่อสตริงส่วนตัว; ผู้เล่นส่วนตัว () {} สตริงสาธารณะ getName () {ชื่อคืน; } โมฆะสาธารณะ setName (ชื่อสตริง) {this.name = name; - การดำเนินการ 1.2CAS เปลี่ยนค่าของมิเตอร์ผ่านการปรับเปลี่ยนที่อยู่ออฟเซ็ตหน่วยความจำ
ใช้ CAS เพื่ออัปเดตด้านบนของสแต็กใน Transferstack ใน Synchronousqueue ในแพ็คเกจพร้อมกันของ Java
/ mechanics ที่ไม่ปลอดภัย private คงที่ sun.misc.unsafe unsafe; headoffset แบบคงที่ครั้งสุดท้ายส่วนตัวคงที่; คงที่ {ลอง {unsafe = sun.misc.unsafe.getunsafe (); คลาส <?> k = transferstack.class; headoffset = unsafe.objectfieldoffset (k.getDeclaredField ("head")); } catch (exception e) {โยนข้อผิดพลาดใหม่ (e); }} // snode head ผันผวน; // อัปเดตด้านบนของสแต็กบูลีน cashead (snode h, snode nh) {return h == head && unsafe.compareandswapobject (นี่, headoffset, h, nh);}; 1.3 การเข้าถึงหน่วยความจำโดยตรง
การเข้าถึงหน่วยความจำโดยตรงของ Unsafe: พื้นที่หน่วยความจำที่เปิดด้วย Unsafe ไม่ได้ใช้พื้นที่ฮีปและแน่นอนว่าไม่มีฟังก์ชั่นการกู้คืนหน่วยความจำอัตโนมัติ ทำให้สามารถใช้ทรัพยากรหน่วยความจำระบบได้อย่างอิสระเช่น C.
2. การวิเคราะห์ซอร์สโค้ดคลาสที่ไม่ปลอดภัย
APIs ของ UNSACE ส่วนใหญ่เป็นวิธีการดั้งเดิมส่วนใหญ่รวมถึงหมวดหมู่ต่อไปนี้:
1) ชั้นเรียนที่เกี่ยวข้อง ส่วนใหญ่ให้ชั้นเรียนและวิธีการทำงานของฟิลด์แบบคงที่
2) วัตถุที่เกี่ยวข้อง ส่วนใหญ่ให้วิธีการทำงานของวัตถุและฟิลด์
3) Arrray ที่เกี่ยวข้อง ส่วนใหญ่ให้วิธีการทำงานของอาร์เรย์และองค์ประกอบในนั้น
4) สหสัมพันธ์พร้อมกัน ส่วนใหญ่ให้บริการดั้งเดิมการซิงโครไนซ์ระดับต่ำเช่น CAS, การตั้งเวลาเธรด, ระเหย, อุปสรรคหน่วยความจำ ฯลฯ
5) หน่วยความจำที่เกี่ยวข้อง มันมีวิธีการเข้าถึงหน่วยความจำโดยตรง (บายพาสจาวาฮีปและจัดการหน่วยความจำท้องถิ่นโดยตรง) ซึ่งสามารถใช้ทรัพยากรหน่วยความจำระบบได้อย่างอิสระเช่น C.
6) ระบบที่เกี่ยวข้อง ส่วนใหญ่จะส่งคืนข้อมูลหน่วยความจำระดับต่ำเช่นขนาดที่อยู่และขนาดหน้าหน่วยความจำ
2.1 คลาสที่เกี่ยวข้อง
// ออฟเซ็ตของแอตทริบิวต์คงที่ใช้ในการอ่านและเขียนแอตทริบิวต์คงที่ในคลาสที่สอดคล้องกันของวัตถุที่สอดคล้องกันพื้นเมือง Long StaticFieldSet (Field F); วัตถุพื้นเมืองสาธารณะ StaticfieldBase (Field F); // ตัดสินว่าชั้นเรียนจะต้องเริ่มต้นบูลีนพื้นเมืองสาธารณะควรมีการกำหนดค่า (ชั้น <?> c); // ตรวจสอบให้แน่ใจว่าชั้นเรียนเป็นโมฆะพื้นเมืองสาธารณะเริ่มต้น classloader loader, ProtectionDomain ProtectionDomain); // กำหนดคลาสที่ไม่ระบุชื่อที่สามารถใช้ในการสร้างคลาส Public Native Class <?> defineanonymousClass (คลาส <s?> hostclass, byte [] data, object [] cppatches);
2.2Object
มีวิธีการต่อไปนี้สำหรับประเภทพื้นฐาน (บูลีน, ไบต์, ถ่าน, สั้น, int, ยาว, ลอย, สองเท่า) และประเภทการอ้างอิงวัตถุใน Java
// รับฟิลด์ออฟเซ็ตของวัตถุสาธารณะพื้นเมือง Long ObjectFieldSet (Field F); // รับค่า int ของที่อยู่วัตถุที่กำหนดออฟเซ็ตสาธารณะ int getint (Object O, Offset ยาว); // ตั้งค่า int ของที่อยู่วัตถุที่กำหนดออฟเซ็ตโมฆะ putint สาธารณะ (วัตถุ O, ออฟเซ็ตยาว, int x);
// สร้างวัตถุ แต่ตัวสร้างจะไม่ถูกเรียก หากคลาสไม่ได้เริ่มต้นคลาสจะเริ่มต้น วัตถุพื้นเมืองสาธารณะ allocateInstance (คลาส <?> CLS) พ่นอินสแตนติเซชัน
2.3 อาเรย์ที่เกี่ยวข้อง
/** * รายงานออฟเซ็ตขององค์ประกอบแรกในการจัดสรรที่เก็บข้อมูลของคลาสอาร์เรย์ที่กำหนด ถ้า {@link #ArrayIndexScale} ส่งคืนค่าที่ไม่ใช่ศูนย์ * สำหรับคลาสเดียวกันคุณอาจใช้ปัจจัยสเกลนั้นพร้อมกับการชดเชยฐาน * นี้เพื่อสร้างออฟเซ็ตใหม่เพื่อเข้าถึงองค์ประกอบของอาร์เรย์ของคลาส * ที่กำหนด * * @See #GetInt (Object, Long, Int) * /// ส่งคืนที่อยู่ออฟเซ็ตขององค์ประกอบแรกในอาร์เรย์ public Native int ArrayBaseOffset (คลาส <?> arrayClass); // บูลีน, ไบต์, สั้น, ถ่าน, ยาว, ลอย, สองเท่า array_boolean_base_offset = theunsafe.arraybaseoffset (บูลีน []. คลาส); /** * รายงานปัจจัยมาตราส่วนสำหรับการระบุองค์ประกอบในการจัดเก็บ * การจัดสรรคลาสอาร์เรย์ที่กำหนด อย่างไรก็ตามอาร์เรย์ของประเภท "แคบ" * โดยทั่วไปจะไม่ทำงานอย่างถูกต้องกับ accessors เช่น {@link * #getByte (วัตถุ, int)} ดังนั้นปัจจัยระดับสำหรับคลาสดังกล่าวจะถูกรายงาน * เป็นศูนย์ * * @See #ArrayBaseOffset * @See #GetInt (วัตถุยาว) * @See #PUTINT (วัตถุ, ยาว, int) * /// ส่งคืนขนาดที่ครอบครองโดยแต่ละองค์ประกอบในอาร์เรย์สาธารณะ // บูลีน, ไบต์, สั้น, ถ่าน, int, ยาว, ลอย, ลอย, สองและวัตถุมีวิธีการต่อไปนี้/** ค่าของ {@code arrayIndexscale (บูลีน []. คลาส)}*/สาธารณะคงที่ ตำแหน่งของแต่ละองค์ประกอบในอาร์เรย์ในหน่วยความจำสามารถอยู่ที่ ArrayBaseOffset และ ArrayIndexscale
2.4 เกี่ยวข้องกับการพร้อมกัน
2.4.1cas เกี่ยวข้อง
CAS: การเปรียบเทียบและการชดเชยที่อยู่ออฟเซ็ตหน่วยความจำ, ค่าที่คาดหวังคาดว่าค่าใหม่ x หากค่าของตัวแปรในเวลาปัจจุบันและค่าที่คาดหวังให้เท่ากันลองอัปเดตค่าของตัวแปรเป็น x ส่งคืนจริงหากการอัปเดตสำเร็จ มิฉะนั้นให้ส่งคืนเท็จ
// อัปเดตค่าตัวแปรเป็น x หากค่าปัจจุบันคาดว่า // o: Object Offset: Offset คาดหวัง: ค่าที่คาดหวัง x: ค่าใหม่สาธารณะ Native Boolean Native SompereandswapObject (Object O, Long Offset, Object, Object, Object X); Public Native Native Boolean Sompereandswapint (Object O, Offset Long, Int คาดหวัง, int x); Public Native Native Boolean Sompoleandswaplong (Object O, ชดเชยยาว, คาดว่ายาว, ยาว x);
เริ่มต้นด้วย Java 8 วิธีการต่อไปนี้มีให้ในไม่ปลอดภัย:
// เพิ่ม public final int getandaddint (Object O, Offset ยาว, int delta) {int v; ทำ {v = getIntvolatile (O, ออฟเซ็ต); } ในขณะที่ (! Compereandswapint (O, Offset, V, V + Delta)); return v;} public final long getandaddlong (Object O, Offset ยาว, Delta ยาว) {Long V; ทำ {v = getLongvolatile (O, ออฟเซ็ต); } ในขณะที่ (! Compereandswaplong (O, Offset, V, V + Delta)); return v;} // ตั้งค่า public final int getandsetint (Object O, Offset ยาว, int newValue) {int v; ทำ {v = getIntvalatile (O, ออฟเซ็ต); } ในขณะที่ (! Compereandswapint (O, Offset, V, NewValue)); return v;} public final long long getandsetlong (Object O, Offset ยาว, Long NewValue) {Long V; ทำ {v = getLongvalatile (O, ออฟเซ็ต); } ในขณะที่ (! เปรียบเทียบและ swaplong (o, ออฟเซ็ต, v, newValue)); return v;} วัตถุสุดท้ายสาธารณะ getandsetObject (Object O, Offset ยาว, Object NewValue) {Object V; ทำ {v = getObjectValatile (O, ออฟเซ็ต); } ในขณะที่ (! CompereandswapObject (O, Offset, V, NewValue)); กลับ V;2.4.2 การจัดตารางเธรดที่เกี่ยวข้อง
// Unblocking Thread Public Native Native unpark (ด้ายวัตถุ); // การปิดกั้นพวงมาลัย Native Public Public (Boolean isabsolute, นาน); // รับวัตถุล็อควัตถุโมฆะ public Native Monitorenter (Object O); // ปล่อยวัตถุล็อคพื้นเมือง
2.4.3 การอ่านและการเขียนที่เกี่ยวข้องผันผวน
มีวิธีการต่อไปนี้สำหรับประเภทพื้นฐาน (บูลีน, ไบต์, ถ่าน, สั้น, int, ยาว, ลอย, สองเท่า) และประเภทการอ้างอิงวัตถุใน Java
// รับการอ้างอิงของตัวแปรจากออฟเซ็ตที่ระบุของวัตถุและใช้ความหมายโหลดของความผันผวน // เทียบเท่ากับรุ่นที่ผันผวนของ getObject (วัตถุ, ยาว) วัตถุดั้งเดิม getObjectVolatile (วัตถุ O, ออฟเซ็ตยาว); // การจัดเก็บข้อมูลอ้างอิงของตัวแปรไปยังออฟเซ็ตที่ระบุของวัตถุและใช้ความหมายที่เก็บข้อมูลของผันผวน // เทียบเท่ากับเวอร์ชันระเหยของ putobject (วัตถุ, ยาว, วัตถุ) โมฆะ putobjectVolatile (วัตถุ O, OFFSET, OBJECT X);
/** * เวอร์ชันของ {@link #putobjectVolatile (วัตถุยาววัตถุ)} * ที่ไม่รับประกันการมองเห็นทันทีของร้านค้าไปยัง * เธรดอื่น ๆ วิธีนี้โดยทั่วไปจะมีประโยชน์เฉพาะในกรณีที่ฟิลด์ * พื้นฐานเป็น Java ผันผวน (หรือถ้าเซลล์อาร์เรย์หนึ่ง * ที่เข้าถึงได้โดยใช้การเข้าถึงที่ผันผวนเท่านั้น) */โมฆะดั้งเดิม PutorderEdObject (Object O, Offset ยาว, Object X); /** เวอร์ชันที่สั่งซื้อ/ขี้เกียจของ {@link #putintvolatile (วัตถุ, ยาว, int)}*/โมฆะดั้งเดิม putorderedint (วัตถุ O, ออฟเซ็ตยาว, int x); /** เวอร์ชันที่สั่งซื้อ/ขี้เกียจของ {@link #putlongvolatile (วัตถุยาวยาว)}*/โมฆะดั้งเดิม putorderedlong (วัตถุ O, ชดเชยยาว, ยาว x);2.4.4 สิ่งกีดขวางหน่วยความจำที่เกี่ยวข้อง
Java 8 ได้รับการแนะนำเพื่อกำหนดอุปสรรคหน่วยความจำเพื่อหลีกเลี่ยงการจัดลำดับรหัสใหม่
// สิ่งกีดขวางหน่วยความจำห้ามการดำเนินการโหลดจากการจัดเรียงใหม่นั่นคือการดำเนินการโหลดก่อนที่สิ่งกีดขวางจะไม่สามารถจัดเรียงใหม่ไปยังสิ่งกีดขวางการดำเนินการโหลดหลังจากที่สิ่งกีดขวางไม่สามารถจัดเรียงใหม่ไปที่ด้านหน้าของการโหลดโมฆะสาธารณะ การดำเนินการจากการจัดเรียงใหม่ไปยังด้านหน้าของอุปสรรคสาธารณะเป็นโมฆะพื้นเมืองฟูลเฟนซ์ ();
2.5 การเข้าถึงหน่วยความจำโดยตรง (หน่วยความจำที่ไม่ใช่กอง)
หน่วยความจำที่จัดสรรโดย allocatememory จำเป็นต้องฟรีด้วยตนเอง (ไม่ได้รีไซเคิลโดย GC)
// (บูลีน, ไบต์, ถ่าน, สั้น, int, ยาว, ลอย, double) มีสองวิธีต่อไปนี้: รับและใส่ // รับค่า int ที่ที่อยู่ที่อยู่สาธารณะ Native int getint (ที่อยู่ยาว); // ตั้งค่า int ที่ที่อยู่ที่อยู่ putint native publit (ที่อยู่ยาว, int x); // รับตัวชี้ท้องถิ่น Long Native GetAddress (ที่อยู่ยาว); // การจัดเก็บตัวชี้ท้องถิ่นไปยังที่อยู่หน่วยความจำ // จัดสรรหน่วยความจำสาธารณะพื้นเมืองยาว allocatememory (Long bytes); // reallocate หน่วยความจำสาธารณะพื้นเมืองยาว reallocatememory (ที่อยู่ยาว, ไบต์ยาว); // เริ่มต้นเนื้อหาความทรงจำ public native setMemory (Object O, Long Long Bytes, Byte Value); // ที่อยู่, ไบต์, ค่า);} // เริ่มต้นเนื้อหาหน่วยความจำโมฆะ public Native Native Copymemory (Object Srcbase, Long Srcoffset, Destbase Object, Long Destoffset, Long Bytes); // เริ่มต้นเนื้อหาความจำสาธารณะ ไบต์);} // การปล่อยหน่วยความจำสาธารณะเป็นโมฆะ freememory (ที่อยู่ยาว);
2.6 ระบบที่เกี่ยวข้อง
// ส่งคืนขนาดของตัวชี้ ค่าผลตอบแทนคือ 4 หรือ 8. ที่อยู่ INT สาธารณะสาธารณะ (); /** ค่าของ {@code addressSize ()}*/สาธารณะคงที่ int สุดท้าย address_size = theunsafe.addressize (); // ขนาดของหน้าหน่วยความจำ Public Native Int Pagesize ();3. วัสดุอ้างอิง
//www.vevb.com/article/140709.htm มาพูดคุยเกี่ยวกับคลาสที่ไม่ปลอดภัยใน java
//www.vevb.com/article/140721.htm Java Magic Class: sun.misc.unsafe
สรุป
ข้างต้นเป็นเนื้อหาทั้งหมดของบทความนี้ ฉันหวังว่าเนื้อหาของบทความนี้จะมีค่าอ้างอิงบางอย่างสำหรับการศึกษาหรือที่ทำงานของทุกคน หากคุณมีคำถามใด ๆ คุณสามารถฝากข้อความไว้เพื่อสื่อสาร ขอบคุณสำหรับการสนับสนุน Wulin.com