คลาสที่ไม่ปลอดภัยคืออะไร?
Java ได้รับการออกแบบมาเป็นสภาพแวดล้อมที่มีการควบคุมที่ปลอดภัย อย่างไรก็ตามเรื่องนี้ฮอตสปอต Java ยังคงมี "แบ็คดอร์" ที่ให้การดำเนินการระดับต่ำที่สามารถจัดการกับหน่วยความจำและเธรดได้โดยตรง คลาส Backdoor นี้ - sun.misc.unsafe - ใช้กันอย่างแพร่หลายในแพ็คเกจของตัวเองโดย JDK เช่น java.nio และ java.util.concurrent อย่างไรก็ตามแบ็คดอร์นี้ไม่แนะนำในสภาพแวดล้อมการผลิตเลย เพราะ API นี้ไม่ปลอดภัยมากไม่เบาและไม่เสถียร คลาสที่ไม่ปลอดภัยนี้ให้มุมมองของโครงสร้างภายในของฮอตสปอต JVM และสามารถแก้ไขได้ บางครั้งมันสามารถใช้เพื่อเรียนรู้โครงสร้างภายในของเครื่องเสมือนโดยไม่ต้องทำการดีบัก C ++ และบางครั้งก็สามารถใช้เป็นเครื่องมือตรวจสอบประสิทธิภาพและการพัฒนา
การแนะนำ
เมื่อเร็ว ๆ นี้ฉันกำลังดูซอร์สโค้ดของแพ็คเกจ Java พร้อมกันและค้นพบคลาสที่ไม่ปลอดภัยเวทมนตร์ ฉันศึกษาอย่างระมัดระวังและแบ่งปันกับคุณที่นี่
คลาสที่ไม่ปลอดภัยอยู่ภายใต้แพ็คเกจ Sun.misc และไม่ได้อยู่ในมาตรฐาน Java อย่างไรก็ตามไลบรารีคลาส Java ขั้นพื้นฐานจำนวนมากรวมถึงห้องสมุดการพัฒนาประสิทธิภาพสูงที่ใช้กันอย่างแพร่หลายได้รับการพัฒนาตามชั้นเรียนที่ไม่ปลอดภัยเช่น Netty, Cassandra, Hadoop, Kafka ฯลฯ คลาสที่ไม่ปลอดภัยมีบทบาทอย่างมากในการปรับปรุงประสิทธิภาพการดำเนินงานของ Java และเพิ่มความสามารถในการดำเนินงานของ Java
คลาสที่ไม่ปลอดภัยทำให้ Java สามารถใช้พื้นที่หน่วยความจำเช่นพอยน์เตอร์ในภาษา C และยังนำปัญหาตัวชี้ การใช้คลาสที่ไม่ปลอดภัยมากเกินไปจะเพิ่มโอกาสในการเกิดข้อผิดพลาดดังนั้น Java จึงไม่แนะนำให้ใช้และแทบจะไม่มีเอกสารอย่างเป็นทางการ Oracle กำลังวางแผนที่จะลบคลาสที่ไม่ปลอดภัยจาก Java 9 และถ้าเป็นเช่นนั้นมันจะใหญ่เกินไป
โดยปกติแล้วจะเป็นการดีที่สุดที่จะไม่ใช้คลาสที่ไม่ปลอดภัยเว้นแต่จะมีจุดประสงค์ที่ชัดเจนและยังมีความเข้าใจในเชิงลึก ในการใช้คลาสที่ไม่ปลอดภัยคุณต้องใช้วิธีการที่ยุ่งยาก คลาสที่ไม่ปลอดภัยใช้รูปแบบซิงเกิลตันและจำเป็นต้องได้รับผ่านวิธีการคงที่ getunsafe () อย่างไรก็ตามคลาสที่ไม่ปลอดภัยได้ จำกัด ไว้ หากเป็นการโทรปกติมันจะทำให้เกิดข้อยกเว้น SecurityException; เฉพาะคลาสที่โหลดโดยตัวโหลดคลาสหลักเท่านั้นที่สามารถเรียกวิธีนี้ได้ ซอร์สโค้ดมีดังนี้:
สาธารณะคงที่ไม่ปลอดภัย getUnsafe () {class var0 = reflection.getCallerClass (); if (! vm.issystemdomainloader (var0.getClassLoader ())) {โยนความปลอดภัยใหม่ ("unSafe"); } else {return theunsafe; -นอกจากนี้ยังมีวิธีการโหลดรหัสผู้ใช้โดยใช้ตัวโหลดคลาสหลักเช่นการตั้งค่าพารามิเตอร์ bootclasspath แต่วิธีที่ง่ายกว่าคือการใช้ Java Reflection ดังนี้:
ฟิลด์ f = unsafe.class.getDeclaredField ("theunsafe"); f.setAccessible (จริง); ไม่ปลอดภัย unsafe = (ไม่ปลอดภัย) f.get (null);หลังจากได้รับอินสแตนซ์ที่ไม่ปลอดภัยเราสามารถทำอะไรก็ได้ที่เราต้องการ คลาสที่ไม่ปลอดภัยมีฟังก์ชั่นต่อไปนี้:
1. การจัดการหน่วยความจำ รวมถึงการจัดสรรหน่วยความจำการปลดปล่อยหน่วยความจำ ฯลฯ
ส่วนนี้รวมถึง allocatememory (allocatememory), reallocatememory (reallocatememory), copymemory (หน่วยความจำสำเนา), freememory (หน่วยความจำฟรี), getaddress (ที่อยู่หน่วยความจำ getget), ที่อยู่ Semantics), Putint (เขียนจำนวนเต็มลงในที่อยู่หน่วยความจำที่ระบุ), putintvolatile (เขียนจำนวนเต็มลงในที่อยู่หน่วยความจำที่ระบุและรองรับความหมายที่ผันผวน), putorderedint (เขียนจำนวนเต็มลงในที่อยู่หน่วยความจำที่ระบุหรือวิธีการล่าช้า) getXXX และ putxxx มีการดำเนินการพื้นฐานที่หลากหลาย
การใช้วิธี CopyMemory เราสามารถใช้วิธีการคัดลอกวัตถุทั่วไปโดยไม่ต้องใช้วิธีการโคลนสำหรับแต่ละวัตถุ แน่นอนว่าวิธีการทั่วไปนี้สามารถคัดลอกวัตถุตื้นเท่านั้น
2. การสร้างอินสแตนซ์วัตถุที่ไม่เป็นทางการ
เมธอด allocateInstance () ให้วิธีอื่นในการสร้างอินสแตนซ์ โดยปกติเราสามารถสร้างอินสแตนซ์วัตถุด้วยใหม่หรือสะท้อน ใช้เมธอด allocateInstance () เพื่อสร้างอินสแตนซ์วัตถุโดยตรงโดยไม่ต้องเรียกตัวสร้างและวิธีการเริ่มต้นอื่น ๆ
สิ่งนี้มีประโยชน์เมื่อ deserializing วัตถุช่วยให้สามารถสร้างใหม่และตั้งค่าฟิลด์สุดท้ายโดยไม่ต้องเรียกตัวสร้าง
3. คลาสการดำเนินการวัตถุและตัวแปร
ส่วนนี้รวมถึง StaticFieldOffset (ชดเชยโดเมนแบบคงที่), defineclass (คลาสนิยาม), defineanonymousClass (นิยามคลาสที่ไม่ระบุชื่อ), ensureclassInitialized (ตรวจสอบการเริ่มต้นคลาส), ObjectFieldOffset (Object Domain Offset) และวิธีอื่น ๆ
ด้วยวิธีการเหล่านี้เราสามารถรับตัวชี้ของวัตถุได้ โดยการชดเชยตัวชี้เราไม่เพียง แต่สามารถแก้ไขข้อมูลที่ชี้ไปที่ตัวชี้โดยตรง (แม้ว่าจะเป็นส่วนตัว) แต่เรายังสามารถค้นหาวัตถุที่ JVM ได้พิจารณาขยะแล้วและสามารถนำกลับมาใช้ใหม่ได้
4. การดำเนินการอาร์เรย์
ส่วนนี้รวมถึง arraybaseoffset (รับที่อยู่ออฟเซ็ตขององค์ประกอบแรกของอาร์เรย์), arrayIndexscale (รับที่อยู่ที่เพิ่มขึ้นขององค์ประกอบในอาร์เรย์) ฯลฯ ArrayBaseOffset ใช้ร่วมกับ ArrayIndexScale และคุณสามารถค้นหาตำแหน่งของแต่ละองค์ประกอบในอาร์เรย์ในหน่วยความจำ
เนื่องจากค่าอาร์เรย์สูงสุดของ Java เป็นจำนวนเต็ม MAX_VALUE วิธีการจัดสรรหน่วยความจำของคลาสที่ไม่ปลอดภัยสามารถใช้ในการใช้อาร์เรย์ขนาดใหญ่สุด ๆ ในความเป็นจริงข้อมูลดังกล่าวถือได้ว่าเป็นอาร์เรย์ C ดังนั้นคุณต้องให้ความสนใจกับการปลดปล่อยหน่วยความจำในเวลาที่เหมาะสม
5. การซิงโครไนซ์แบบมัลติเธรด รวมถึงกลไกการล็อคการดำเนินการ CAS ฯลฯ
ส่วนนี้รวมถึง MonitorEnter, Trymonitorenter, Monitorexit, Compereandswapint, เปรียบเทียบและวิธีอื่น ๆ
ในหมู่พวกเขา Monitorenter, Trymonitorenter และ Monitorexit ได้รับการทำเครื่องหมายว่าเลิกใช้แล้วและไม่แนะนำ
การทำงาน CAS ของคลาสที่ไม่ปลอดภัยอาจถูกใช้มากที่สุดและเป็นวิธีการแก้ปัญหาใหม่สำหรับกลไกการล็อคของ Java ตัวอย่างเช่น Atomicinteger และคลาสอื่น ๆ ทั้งหมดถูกนำไปใช้ด้วยวิธีนี้ วิธีการเปรียบเทียบและ Atomic เป็นอะตอมซึ่งสามารถหลีกเลี่ยงกลไกการล็อคหนักและปรับปรุงประสิทธิภาพของรหัส นี่คือการล็อคในแง่ดีซึ่งมักจะเชื่อว่าในกรณีส่วนใหญ่ไม่มีเงื่อนไขการแข่งขันและหากการดำเนินการล้มเหลวมันจะยังคงลองอีกครั้งจนกว่าจะประสบความสำเร็จ
6. ระงับและกู้คืน
ส่วนนี้รวมถึง Park, Unpark และวิธีอื่น ๆ
ระงับเธรดผ่านวิธีการอุทยาน หลังจากโทรไปที่สวนสาธารณะเธรดจะบล็อกจนกว่าจะหมดเวลาหรือขัดจังหวะ unpark สามารถยุติเธรดที่รอดำเนินการเพื่อกู้คืนเป็นปกติ การดำเนินการระงับบนเธรดในกรอบการทำงานพร้อมกันทั้งหมดถูกห่อหุ้มในคลาส Locksupport มีวิธีการแพ็ครุ่นต่าง ๆ ในคลาส locksupport แต่ในที่สุดวิธีการ unsafe.park () เรียกว่า
7. สิ่งกีดขวางหน่วยความจำ
ส่วนนี้รวมถึงการโหลด, storefence, fullfence และวิธีอื่น ๆ นี่คือการแนะนำใหม่ใน Java 8 เพื่อกำหนดอุปสรรคหน่วยความจำเพื่อหลีกเลี่ยงการจัดลำดับรหัสใหม่
LoadFence () หมายความว่าการดำเนินการโหลดทั้งหมดก่อนที่วิธีการจะเสร็จสมบูรณ์ก่อนที่จะมีสิ่งกีดขวางหน่วยความจำ ในทำนองเดียวกัน storefence () หมายความว่าการดำเนินการร้านค้าทั้งหมดก่อนที่วิธีนี้จะเสร็จสมบูรณ์ก่อนที่จะมีสิ่งกีดขวางหน่วยความจำ FullFence () หมายความว่าการดำเนินการโหลดและการจัดเก็บทั้งหมดก่อนที่วิธีการจะเสร็จสมบูรณ์ก่อนที่จะมีสิ่งกีดขวางหน่วยความจำ
สรุป
ข้างต้นเป็นเนื้อหาทั้งหมดของบทความนี้ ฉันหวังว่าเนื้อหาของบทความนี้จะมีค่าอ้างอิงบางอย่างสำหรับการศึกษาหรือที่ทำงานของทุกคน หากคุณมีคำถามใด ๆ คุณสามารถฝากข้อความไว้เพื่อสื่อสาร ขอบคุณสำหรับการสนับสนุน Wulin.com