java的unsafe_java安全设置

java的unsafe_java安全设置前段时间因为看JUC的源码,里面有大量关于unsafe的操作,所以就来看看了.写点笔记总结下:unsafe可以帮我们直接去操作硬件资源,当然了是借助java的jit来进行的,官方不推荐使用,因为不安全,例如你使用unsafe创建一个超级大的数组,但是这个数组jvm是不管理的,只能你自己操作,容易oom,也不利于资源的回收.好了,下面我们来看代码,1.获取unsafe//1.最简单…

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全家桶1年46,售后保障稳定

前段时间因为看JUC的源码,里面有大量关于unsafe的操作,所以就来看看了.写点笔记总结下(本文基于jdk1.8):

unsafe可以帮我们直接去操作硬件资源,当然了是借助java的jit来进行的,官方不推荐使用,因为不安全,例如你使用unsafe创建一个超级大的数组,但是这个数组jvm是不管理的,只能你自己操作,容易oom,也不利于资源的回收.

好了,下面我们来看代码,

1.获取unsafe

//1.最简单的使用方式是基于反射获取Unsafe实例
Field f = Unsafe.class.getDeclaredField("theUnsafe");
f.setAccessible(true);
Unsafe unsafe = (Unsafe) f.get(null);

Jetbrains全家桶1年46,售后保障稳定

2.获取unsafe

private static Unsafe unsafe = null;
private static Field getUnsafe = null;

static {
    try {
        getUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
        getUnsafe.setAccessible(true);
        unsafe = (Unsafe) getUnsafe.get(null);
    } catch (NoSuchFieldException e) {
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    }
}

随便只要你高兴,都可以获取到unsafe,因为涉及到unsafe 的权限问题,所以,我们只能使用这种方式获取,不然就是权限异常,

操作方法:

/**
 * 操作数组:
 * 可以获取数组的在内容中的基本偏移量(arrayBaseOffset),获取数组内元素的间隔(比例),
 * 根据数组对象和偏移量获取元素值(getObject),设置数组元素值(putObject),示例如下。
 */
String[] strings = new String[]{"1", "2", "3"};
long i = unsafe.arrayBaseOffset(String[].class);
System.out.println("string[] base offset is :" + i);

//every index scale
long scale = unsafe.arrayIndexScale(String[].class);
System.out.println("string[] index scale is " + scale);

//print first string in strings[]
System.out.println("first element is :" + unsafe.getObject(strings, i));

//set 100 to first string
unsafe.putObject(strings, i + scale * 0, "100");

//print first string in strings[] again
System.out.println("after set ,first element is :" + unsafe.getObject(strings, i + scale * 0));

/**
 * 对象操作
 * 实例化Data
 *
 * 可以通过类的class对象创建类对象(allocateInstance),获取对象属性的偏移量(objectFieldOffset)
 * ,通过偏移量设置对象的值(putObject)
 *
 * 对象的反序列化
 * 当使用框架反序列化或者构建对象时,会假设从已存在的对象中重建,你期望使用反射来调用类的设置函数,
 * 或者更准确一点是能直接设置内部字段甚至是final字段的函数。问题是你想创建一个对象的实例,
 * 但你实际上又不需要构造函数,因为它可能会使问题更加困难而且会有副作用。
 *
 */
//调用allocateInstance函数避免了在我们不需要构造函数的时候却调用它
Data data = (Data) unsafe.allocateInstance(Data.class);
data.setId(1L);
data.setName("unsafe");
System.out.println(data);

//返回成员属性在内存中的地址相对于对象内存地址的偏移量
Field nameField = Data.class.getDeclaredField("name");
long fieldOffset = unsafe.objectFieldOffset(nameField);
//putLong,putInt,putDouble,putChar,putObject等方法,直接修改内存数据(可以越过访问权限)
unsafe.putObject(data,fieldOffset,"这是新的值");
System.out.println(data.getName());


/**
 * 我们可以在运行时创建一个类,比如从已编译的.class文件中。将类内容读取为字节数组,
 * 并正确地传递给defineClass方法;当你必须动态创建类,而现有代码中有一些代理, 这是很有用的
 */
File file = new File("C:\\workspace\\idea2\\disruptor\\target\\classes\\com\\onyx\\distruptor\\test\\Data.class");
FileInputStream input = new FileInputStream(file);
byte[] content = new byte[(int)file.length()];
input.read(content);
Class c = unsafe.defineClass(null, content, 0, content.length,null,null);
c.getMethod("getId").invoke(c.newInstance(), null);



/**
 * 内存操作
 * 可以在Java内存区域中分配内存(allocateMemory),设置内存(setMemory,用于初始化),
 * 在指定的内存位置中设置值(putInt\putBoolean\putDouble等基本类型)
 */
//分配一个8byte的内存
long address = unsafe.allocateMemory(8L);
//初始化内存填充1
unsafe.setMemory(address, 8L, (byte) 1);
//测试输出
System.out.println("add byte to memory:" + unsafe.getInt(address));
//设置0-3 4个byte为0x7fffffff
unsafe.putInt(address, 0x7fffffff);
//设置4-7 4个byte为0x80000000
unsafe.putInt(address + 4, 0x80000000);
//int占用4byte
System.out.println("add byte to memory:" + unsafe.getInt(address));
System.out.println("add byte to memory:" + unsafe.getInt(address + 4));

/**
 * CAS操作
 * Compare And Swap(比较并交换),当需要改变的值为期望的值时,那么就替换它为新的值,是原子
 * (不可在分割)的操作。很多并发框架底层都用到了CAS操作,CAS操作优势是无锁,可以减少线程切换耗费
 * 的时间,但CAS经常失败运行容易引起性能问题,也存在ABA问题。在Unsafe中包含compareAndSwapObject、
 * compareAndSwapInt、compareAndSwapLong三个方法,compareAndSwapInt的简单示例如下。
 */
Data data = new Data();
data.setId(1L);
Field id = data.getClass().getDeclaredField("id");
long l = unsafe.objectFieldOffset(id);
id.setAccessible(true);
//比较并交换,比如id的值如果是所期望的值1,那么就替换为2,否则不做处理
unsafe.compareAndSwapLong(data,1L,1L,2L);
System.out.println(data.getId());

/**
 * 常量获取
 *
 * 可以获取地址大小(addressSize),页大小(pageSize),基本类型数组的偏移量
 * (Unsafe.ARRAY_INT_BASE_OFFSET\Unsafe.ARRAY_BOOLEAN_BASE_OFFSET等)、
 * 基本类型数组内元素的间隔(Unsafe.ARRAY_INT_INDEX_SCALE\Unsafe.ARRAY_BOOLEAN_INDEX_SCALE等)
 */
//get os address size
System.out.println("address size is :" + unsafe.addressSize());
//get os page size
System.out.println("page size is :" + unsafe.pageSize());
//int array base offset
System.out.println("unsafe array int base offset:" + Unsafe.ARRAY_INT_BASE_OFFSET);



/**
 * 线程许可
 * 许可线程通过(park),或者让线程等待许可(unpark),
 */
Thread packThread = new Thread(() -> {
    long startTime = System.currentTimeMillis();
    //纳秒,相对时间park
    unsafe.park(false,3000000000L);
    //毫秒,绝对时间park
    //unsafe.park(true,System.currentTimeMillis()+3000);

    System.out.println("main thread end,cost :"+(System.currentTimeMillis()-startTime)+"ms");
});
packThread.start();
TimeUnit.SECONDS.sleep(1);
//注释掉下一行后,线程3秒数后进行输出,否则在1秒后输出
unsafe.unpark(packThread);

/**
 * Java数组大小的最大值为Integer.MAX_VALUE。使用直接内存分配,我们创建的数组大小受限于堆大小;
 * 实际上,这是堆外内存(off-heap memory)技术,在java.nio包中部分可用;
 *
 * 这种方式的内存分配不在堆上,且不受GC管理,所以必须小心Unsafe.freeMemory()的使用。
 * 它也不执行任何边界检查,所以任何非法访问可能会导致JVM崩溃
 */
public class SuperArray {

    private static Unsafe unsafe = null;
    private static Field getUnsafe = null;

    static {
        try {
            getUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
            getUnsafe.setAccessible(true);
            unsafe = (Unsafe) getUnsafe.get(null);
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }


    private final static int BYTE = 1;

    private long size;
    private long address;

    public SuperArray(long size) {
        this.size = size;
        address = unsafe.allocateMemory(size * BYTE);
    }

    public void set(long i, byte value) {
        unsafe.putByte(address + i * BYTE, value);
    }

    public int get(long idx) {
        return unsafe.getByte(address + idx * BYTE);
    }

    public long size() {
        return size;
    }


    public static void main(String[] args) {
        long SUPER_SIZE = (long)Integer.MAX_VALUE * 2;
        SuperArray array = new SuperArray(SUPER_SIZE);
        System.out.println("Array size:" + array.size()); // 4294967294
        int sum=0;
        for (int i = 0; i < 100; i++) {
            array.set((long)Integer.MAX_VALUE + i, (byte)3);
            sum += array.get((long)Integer.MAX_VALUE + i);
        }
        System.out.println(sum);
    }



}

如果您觉得写得不多, 可以点个赞吗?

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/200890.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • 王者荣耀语音文件下载

    王者荣耀语音文件下载

  • 非主流免费播放器|免费QQ空间播放器代码|非主流播放器

    非主流免费播放器|免费QQ空间播放器代码|非主流播放器 script type=”text/javascript”>…google_ad_client = “pub-2372065995666058”;/**//* btttttttttttt */google_ad_slot = “7097305745”;google_ad_width = 468;google_ad_height = 15;//–>script>script type

  • jrtplib接收rtcp_印象笔记是哪国的

    jrtplib接收rtcp_印象笔记是哪国的原博主博客地址:https://blog.csdn.net/qq21497936本文章博客地址:https://blog.csdn.net/qq21497936/article/details/84785284目录前话2019年12月6日补充JRTPLIB介绍CMake介绍JThread编译步骤一:下载JThread1.3.1并解压,如下图:步骤二:新建jthre…

  • WiFi 标准「建议收藏」

    WiFi 标准「建议收藏」目录802.11a/b/g/n/ac/axWiFi6主要特点802.11a/b/g/n/ac/ax参考:802.11a/b/g/n/ac是什么以及它们有什么区别802.11是一种无线局域网标准,802.11a/b/g/n/ac都是由802.11发展而来的。不同的后缀代表着不同的物理层标准工作频段和不同的传输速率,也就是说它们的物理层和传输速度不同。WiFi标准 协议 工作频率 信号 最大传输速率 802.11 …

  • MFC入门教程(深入浅出MFC)

    以下是我从其他网站中学的内容,后有相应的网站学习链接地址,可供学习1.选择菜单项File->New->Project,弹出“NewProject”对话框。 2.左侧面板中InstalledTemplated的VisualC++下选择MFC,中间窗口中选择MFCApplication,然后在下面的Name编辑框中键入工程名称,本例取名“Addition”,在Location编

  • es集群搭建_k8s和docker搭建es集群

    es集群搭建_k8s和docker搭建es集群单机的elasticsearch做数据存储,必然面临两个问题:海量数据存储问题、单点故障问题。ES集群搭建_使用docker-海量数据存储问题:将索引库从逻辑上拆分为N个分片(shard),存储到多个节点-单点故障问题:将分片数据在不同节点备份(replica)ES集群介绍为什么需要集群ES集群相关概念搭建ES集群集群职责划分集群脑裂问题…

    2022年10月12日

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号