匿名内部类/Lambda Java和Kotlin谁会导致内存泄漏?

news2024/11/26 0:37:18

前言

内存泄漏是程序界永恒的话题,对于Android开发来说尤为重要,想让你的App表现得更优雅,了解并治理内存泄漏问题势在必行。
通过本篇文章,你将了解到:

  1. 何为内存泄漏?
  2. Android 常见内存泄漏场景
  3. Java匿名内部类会导致泄漏吗?
  4. Java的Lambda是否会泄漏?
  5. Kotlin匿名内部类会导致泄漏吗?
  6. Kotlin的Lambda是否会泄漏?
  7. Kotlin高阶函数的会泄漏吗?
  8. 内存泄漏总结

1. 何为内存泄漏?

简单内存分布

image.png
如上图,系统在分配内存的时候,会寻找空闲的内存块进行分配(有些需要连续的存储空间)。
分配成功,则标记该内存块被占用,当内存块不再被使用时,则置为空闲。

占用和被占用涉及到内存的分配和释放,在不同的程序语言里有不同的封装。

C 分配/释放内存函数:

分配:malloc函数
释放:free函数

C++ 分配/释放内存函数:

分配:new函数
释放:delete函数

C/C++ 需要程序员手动分配和释放内存,而我们知道手动的东西容易遗漏。

如果一块内存永远不再被使用,但是又没有被回收,那么这段内存一直无法被复用,这就是内存泄漏

Java内存泄漏

鉴于C/C++ 需要手动释放内存容易遗漏最后造成内存泄漏的问题,Java在内存回收机制上做了改进:
不需要程序员手动释放内存,JVM系统有GC机制,定期扫描不再被引用的对象,将对象所占的的内存空间释放。

你可能会有疑惑:既然都有GC机制了,为啥还会有泄漏呢?
因为GC是根据可达性来判别对象是否还在使用,当GC动作发生时,如果一个对象被gc root对象持有,那么它是无法被回收的。

image.png

如上图,obj1~obj5被gc root 直接或间接持有,它们是不会被回收的,而obj6~obj10 没有被gc root持有,它们是可以被回收的。

常见的作为gc root的对象

JVM在发起GC 动作的时候,需要从gc root出发判别对象的可达性,常见的gc root对象:
image.png

开发里排查内存泄漏涉及比较多的gc root是:

JNI 变量、静态引用、活动的线程

如果不涉及到JNI开发,我们更多关注的是后两者。

到此,我们知道了Java内存泄漏的缘由:

不再被使用的对象,因为一些不当的操作导致其被gc root持有无法被回收,最终内存泄漏

2. Android 常见内存泄漏场景

经典泄漏问题

Handler使用不当泄漏

先看耳熟能详的Demo:

public class ThirdActivity extends AppCompatActivity {
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_third);
    }

    private Handler handler = new Handler() {
        @Override
        public void handleMessage(@NonNull Message msg) {
            super.handleMessage(msg);
            Log.d("fish", "hello world");
        }
    };
}

上面有个匿名内部类,继承自Handler。
我们知道在Java里,匿名内部类默认持有外部类引用,并且此处编译器会有提示:

This Handler class should be static or leaks might occur (anonymous android.os.Handler)

意思是:

推荐使用静态类来继承Handler,因为使用匿名内部类可能会有内存泄漏风险

我们做个实验,操作步骤:打开Activity,关闭Activity,观察内存使用状况,是否发生内存泄漏。

问题来了:以上代码会有内存泄漏吗?
答案当然是否定的,因为我们并没有使用handler对象。

将代码改造一下,onCreate里新增如下代码:

        handler.sendEmptyMessageDelayed(2, 5000);

此时会发生内存泄漏吗?
当然肉眼是无法证明是否泄漏的,我们通过使用Android Studio自带的性能分析工具:Profiler 进行分析:
image.png
果然Activity发生泄漏了。

如何规避此种场景下的内存泄漏呢?

public class ThirdActivity extends AppCompatActivity {
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_third);

        new MyHandler().sendEmptyMessageDelayed(2, 5000);
    }

    static class MyHandler extends Handler {
        @Override
        public void handleMessage(@NonNull Message msg) {
            super.handleMessage(msg);
            Log.d("fish", "hello world");
        }
    }
}

使用静态内部类实现Handler功能,静态内部类默认没有持有外部类引用。
检测结果,没有发生内存泄漏。
image.png

无论是匿名内部类还是静态内部类,都没有显式地持有外部类引用,既然匿名内部类会发生泄漏,那为啥还需要匿名内部类呢?
匿名内部类优点:

  1. 无需重新定义新的具名类
  2. 符合条件的匿名内部类可以转为Lambda表达式,简洁
  3. 匿名内部类可以直接访问外部类引用

假若现在需要在收到message时弹出个Toast。
对于匿名内部类的实现很简单:

    private Handler handler = new Handler() {
        @Override
        public void handleMessage(@NonNull Message msg) {
            super.handleMessage(msg);
            Toast.makeText(ThirdActivity.this, "hello world", Toast.LENGTH_SHORT).show();
        }
    };

因为它默认持有外部类引用。

而对于静态内部类,则提示无法访问外部类对象。
image.png
需要给它单独传递外部类引用,相较于匿名内部类比较繁琐。

Handler 泄漏的本质原因

对于当前的Demo来说,匿名内部类隐式持有外部类引用,我们需要需要找到匿名内部类被哪个gc root直接/间接地持有了。
image.png

由图可知,最终Activity被Thread持有了。
简单回顾源码流程:

  1. 构造Handler对象时会绑定当前线程的Looper,Looper里持有MessageQueue引用
  2. 当前线程的Looper存储在Thread里的ThreadLocal
  3. 当Handler发送消息的时候,构造Message对象,而该Message对象持有Handler引用
  4. Message对象将会被放置在MessageQueue里
  5. 由此推断,Thread将会间接持有Handler,而Handler又持有外部类引用,最终Thread将会间接持有外部类引用,导致了泄漏

线程使用不当泄漏

先看简单Demo:

public class ThirdActivity extends AppCompatActivity {
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_third);

        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(200000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        });
    }
}

问:上述代码会发生内存泄漏吗?
答:当然不会,因为线程并没有开启。

public class ThirdActivity extends AppCompatActivity {
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_third);

        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(200000);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        }).start();
    }
}

再分析分析,会有内存泄漏吗?
与之前的Handler一致,匿名内部类会持有外部类的引用,而匿名内部类本身又被线程持有,因此会发生泄漏。

如何规避此种场景下的内存泄漏呢?

有两种方式:
第一种:使用静态内部类替换匿名内部类
此种方式同Handler处理类似。

第二种:使用Lambda替换匿名内部类

public class ThirdActivity extends AppCompatActivity {
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_third);

        new Thread(() -> {
            try {
                Thread.sleep(200000);
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }).start();
    }
}

Lambda表达式没有隐式持有外部类,因此此种场景下不会有内存泄漏风险。

注册不当内存泄漏

模拟一个简单下载过程,首先定义一个下载管理类:

public class DownloadManager {
   private DownloadManager() {
   }
   static class Inner {
      private static final DownloadManager ins = new DownloadManager();
   }
   public static DownloadManager getIns() {
      return Inner.ins;
   }
   private HashMap<String, DownloadListener> map = new HashMap();
   //模拟注册
   public void download(DownloadListener listener, String path) {
      map.put(path, listener);
      new Thread(() -> {
         //模拟下载
         listener.onSuc();
      }).start();
   }
}

interface DownloadListener {
   void onSuc();
   void onFail();
}

外部传入下载路径,下载成功后通知外界调用者:

public class ThirdActivity extends AppCompatActivity {
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_third);

        DownloadManager.getIns().download(new DownloadListener() {
            @Override
            public void onSuc() {
                //更新UI
            }
            @Override
            public void onFail() {
            }
        }, "hello test");
    }
}

因为需要在下载回调时更新UI,因此选择匿名内部类接收回调,而因为该匿名内部类被静态变量:DownloadManager.ins 持有。
也就是说:

静态变量作为gc root,间接持有匿名内部类,最终持有Activity导致了泄漏

如何规避此种场景下的内存泄漏呢?

有两种方式:

  1. 静态内部类持有Activity弱引用
  2. DownloadManager提供反注册方式,当Activity销毁时反注册从Map里移除回调

3. Java匿名内部类会导致泄漏吗?

线程持有匿名内部类对象

内存泄漏的一些前置知识已经过了一遍,接下来我们从字节码的角度分别分析匿名内部类、Lambda表达式、高阶函数是否存在泄漏问题。
先看Demo:

public class ThirdActivity extends AppCompatActivity {
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_third);
        new Thread(new Runnable() {
            @Override
            public void run() {
                Log.d("fish", "hello world");
            }
        }).start();
    }
}

当我们进入Activity,而后又退出时,猜猜会发生泄漏吗?
有些小伙伴会说:当然了,线程持有匿名内部类对象,而匿名内部类对象又持有外部类(Activity)引用。
实际上是此处的线程并没有执行耗时任务,很快就结束了,系统回收Activity对象时线程已经结束了,不会再持有匿名内部类对象了。

怎么确定匿名内部类持有外部类引用呢?
一个很直观的表现:

在匿名内部类里访问外部类实例变量,若是编译器没有提示错误,则可以认为匿名内部类持有外部类引用

当然,想要看到石锤就得从字节码出发了。

Java匿名内部类Class文件

build一下并查找Javac的产物:在/build/intermediates/javac 开头的目录下
image.png
这里是看不到匿名内部类的,需要到文件浏览器里查找。
image.png

可以看出,我们只是声明了一个ThirdActivity类,但是生成了两个Class文件,其中一个是匿名内部类生成的,通常命名方式为:外部类名+“$”+“第几个内部类”+“.class”。
拖到Studio里查看内容:
image.png

显然匿名内部类构造函数形参里有外部类的类型,当构造匿名内部类时会传递进去并赋值给匿名内部类的成员变量。

Java匿名内部类字节码

查看字节码方式有多种,可以用javap命令:

javap -c ThirdActivity$1.class

也可以在Android Studio里下载字节码插件:
image.png
在源文件上右键选择查看字节码:

image.png

可以看出:

  1. New 指令创建匿名内部类对象并复制到操作数栈顶
  2. 加载外部类对象到操作数栈顶
  3. 调用匿名内部类构造函数,并将第2步的栈顶对象传入

如此一来,匿名内部类创建了,并且持有了外部类引用。

回到最初问题,Java匿名内部类是否会泄漏呢?

当外部类销毁的时候,如果匿名内部类被gc root 持有(间接/直接),那么将会发生内存泄漏

4. Java的Lambda是否会泄漏?

线程持有Lambda对象

将上小结的匿名内部类改造为Lambda(注:不是所有的匿名内部类都可以转为Lambda表达式)

public class ThirdActivity extends AppCompatActivity {
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_third);
        new Thread(() -> {
            Log.d("fish", "hello world");
            Log.d("fish", "hello world2");
        }).start();
    }
}

Java Lambda生成的Class文件

Java Lambda并没有生成Class文件。

Java Lambda字节码

image.png
image.png

Java Lambda并没有生成Class文件,而是通过INVOKEDYNAMIC 指令动态生成Runnable对象,最后传入Thread里。
可以看出,此时生成的Lambda并没有持有外部类引用。

Java Lambda显式持有外部类引用

public class ThirdActivity extends AppCompatActivity {
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_third);
        new Thread(() -> {
            //显式持有外部类引用
            Log.d("fish", ThirdActivity.class.getName());
        }).start();
    }
}

再查看字节码:
image.png

可以看出,传入了外部类引用。
回到最初问题,Java Lambda是否会泄漏呢?

  1. Lambda没有隐式持有外部类引用,
  2. 若在Lambda内显式持有外部类引用,那么此时和Java 匿名内部类类似的,当外部类销毁的时候,如果Lambda被gc root 持有(间接/直接),那么将会发生内存泄漏

5. Kotlin匿名内部类会导致泄漏吗?

线程持有匿名内部类对象

class FourActivity : AppCompatActivity() {
    private lateinit var binding: ActivityFourBinding
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityFourBinding.inflate(layoutInflater)
        setContentView(binding.root)
        Thread(object : Runnable {
            override fun run() {
                println("hello world")
            }
        }).start()
    }
}

此时匿名内部类会持有外部类引用吗?
先从生成的Class文件入手。

Kotlin 匿名内部类生成的Class文件

Kotlin编译生成的Class目录:build/tmp/kotlin-classes/
查找生成的Class文件:
image.png
我们发现生成了Class文件,命名规则:外部类名+方法名+第几个匿名内部类+“.class”

Kotlin 匿名内部类字节码

image.png
可以看出,并没有持有外部类引用。

Kotlin 匿名内部类显式持有外部类引用

class FourActivity : AppCompatActivity() {
    val name = "fish"
    private lateinit var binding: ActivityFourBinding
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityFourBinding.inflate(layoutInflater)
        setContentView(binding.root)
        Thread(object : Runnable {
            override fun run() {
                println("hello world $name")
            }
        }).start()
    }
}

查看字节码:
image.png
由此可见,构造函数携带了外部类引用。

回到最初问题,Kotlin 匿名内部类是否会泄漏呢?

  1. Kotlin 匿名内部类没有隐式持有外部类引用,
  2. 若在Kotlin 匿名内部类内显式持有外部类引用,那么此时和Java 匿名内部类类似的,当外部类销毁的时候,如果Lambda被gc root 持有(间接/直接),那么将会发生内存泄漏

6. Kotlin的Lambda是否会泄漏?

线程持有Lambda对象

class FourActivity : AppCompatActivity() {
    private lateinit var binding: ActivityFourBinding
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityFourBinding.inflate(layoutInflater)
        setContentView(binding.root)
        Thread { println("hello world ") }
    }
}

此时Lambda会持有外部类引用吗?
先从生成的Class文件入手。

Kotlin Lambda生成的Class文件

Kotlin Lambda 并没有生成Class文件。

Kotlin Lambda字节码

image.png
image.png
可以看出,并没有隐式持有外部类引用。

Kotlin Lambda显式持有外部类引用

class FourActivity : AppCompatActivity() {
    val name = "fish"
    private lateinit var binding: ActivityFourBinding
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityFourBinding.inflate(layoutInflater)
        setContentView(binding.root)
        Thread { println("hello world $name") }
    }
}

查看字节码:
image.png
由此可见,构造函数携带了外部类引用。

回到最初问题,Kotlin Lambda是否会泄漏呢?

和Java Lambda表述一致

7. Kotlin高阶函数的会泄漏吗?

什么是高阶函数?

将函数类型当做形参或返回值的函数称为高阶函数。
高阶函数在Kotlin里无处不在,是Kotlin简洁写法的一大利器。

高阶函数生成的Class文件

class FourActivity : AppCompatActivity() {
    private lateinit var binding: ActivityFourBinding
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityFourBinding.inflate(layoutInflater)
        setContentView(binding.root)
        test {
            println("$it")
        }
    }
    //高阶函数作为形参
    private fun test(block:(String) -> Unit) {
        block.invoke("fish")
    }
}

很简单的一个高阶函数,查看生成的Class文件:
image.png
查看Kotlin Bytecode内容:

final class com/fish/perform/FourActivity$onCreate$1 extends kotlin/jvm/internal/Lambda implements kotlin/jvm/functions/Function1 {

继承自Lambda,并实现了Function1接口。
它的构造函数并没有形参,说明不会传入外部类引用。

高阶函数的字节码

image.png
和之前分析的匿名内部类和Lambda不同的是(虽然高阶函数也可以用Lambda简化表达):涉及到了GETSTATIC指令。
该指令意思是从静态变量里获取高阶函数的引用,在高阶函数的字节码加载的时候就已经将静态变量初始化:
image.png
可以这么理解:

  1. 高阶函数的Class加载的时候会初始化实例,并将该实例存储在静态变量里
  2. 当外部调用高阶函数时,从静态变量里获取高阶函数实例

高阶函数显式持有外部类引用

class FourActivity : AppCompatActivity() {
    val name="fish"
    private lateinit var binding: ActivityFourBinding
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityFourBinding.inflate(layoutInflater)
        setContentView(binding.root)
        test {
            println("$it:$name")
        }
    }
    //高阶函数作为形参
    private fun test(block:(String) -> Unit) {
        block.invoke("fish")
    }
}

查看字节码:
image.png
构造函数持有了外部类引用,此时并没有生成静态变量(没必要生成,若生成了就是妥妥的内存泄漏了)

回到最初问题,高阶函数是否会泄漏呢?

1.高阶函数没有隐式持有外部类引用,
2. 若在高阶函数内显式持有外部类引用,那么此时和Java 匿名内部类类似的,当外部类销毁的时候,如果高阶函数被gc root 持有(间接/直接),那么将会发生内存泄漏

8. 内存泄漏总结

image.png

简单理解内存泄漏:

  1. 长生命周期的对象持有短生命周期的对象,导致短生命周期的对象在生命周期结束后没有被及时回收,导致内存无法复用,最终泄漏
  2. 合理地释放对短生命周期对象的引用

代码基本都在正文里,此处就不贴github链接了,有疑惑请评论/私信
后续将会继续输出APT/AGP等全系列流程文章,敬请期待。

您若喜欢,请点赞、关注、收藏,您的鼓励是我前进的动力

持续更新中,和我一起步步为营系统、深入学习Android/Kotlin

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/765680.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Vue3警告提示(Alert)

可自定义设置以下属性&#xff1a; 警告提示内容&#xff08;message&#xff09;&#xff0c;类型&#xff1a;string | slot&#xff0c;默认&#xff1a;‘’警告提示的辅助性文字介绍&#xff08;description&#xff09;&#xff0c;类型&#xff1a;string | slot&#…

14 - 堆栈 - 小顶堆

前面我们学习了线性结构的栈, 今天我们来学习一种非线性结构-堆 堆的定义 堆是一种非线性结构,可以把堆看作一棵二叉树, 堆的存储可以使用数组来存放! 堆的分类 堆可以分为大顶堆和小顶堆。 大顶堆: 每个结点的值都大于或等于其左右孩子结点的值。 小顶堆: 每个结点的值…

目标检测——yolo系列算法

目录 yolo算法yolo算法思想yolo的网络结构网络输入网络输出7x7网格30维向量 yolo模型的训练训练样本的构建损失函数模型训练 模型预测yolo总结 yoloV2预测更准确(better)batch normalization使用高分辨率图像微调分类模型采样Anchor Boxes聚类提取anchor尺度边框位置的预测细粒…

设计模式之单例模式的实现形式、弊端以及可替代的解决方案。

你好&#xff0c;我是爱养猫的程序员雪球&#xff0c;今天与你分享设计模式之单例模式。 单例模式是指一个类只允许创建一个对象&#xff08;或实例&#xff09;的模式。它在很多应用场景中具有重要作用&#xff0c;例如处理资源访问冲突&#xff08;如日志文件写入&#xff09…

生信分析案例 Python简明教程 | 视频12

开源生信 Python教程 生信专用简明 Python 文字和视频教程 源码在&#xff1a;https://github.com/Tong-Chen/Bioinfo_course_python 目录 背景介绍 编程开篇为什么学习Python如何安装Python如何运行Python命令和脚本使用什么编辑器写Python脚本Python程序事例Python基本语法 数…

安徽华云安荣获合肥市大数据企业认定

日前&#xff0c;合肥市数据资源局公布了2023年度合肥市大数据企业认定名单&#xff0c;华云安子公司安徽华云安科技有限公司&#xff08;以下简称安徽华云安&#xff09;被成功认定为合肥市大数据企业。 据悉&#xff0c;合肥市大数据企业是合肥市为扶持和鼓励大数据企业发展&…

Android 自定义带箭头对话框背景

简介 自定义drawable&#xff0c;带箭头对话框背景&#xff0c;三角形矩形组合。应用于对话框背景、提示语背景等。 可设置箭头显示方向、箭头大小、箭头导圆角尺寸、矩形尺寸、矩形导圆角尺寸、背景颜色、drawable padding值&#xff08;影响宿主控件padding&#xff09;。 …

欧姆龙以太网模块如何设置ip连接 Kepware opc步骤

在数字化和自动化的今天&#xff0c;PLC在工业控制领域的作用日益重要。然而&#xff0c;PLC通讯口的有限资源成为了困扰工程师们的问题。为了解决这一问题&#xff0c;捷米特推出了JM-ETH-CP转以太网模块&#xff0c;让即插即用的以太网通讯成为可能&#xff0c;不仅有效利用了…

排序算法之冒泡排序详解-python版

冒泡排序&#xff1a;通过比较2个相邻元素之间的大小&#xff0c;交换元素顺序&#xff0c;从而达到排序目的。 从百度百科摘抄下来的冒泡排序原理如下&#xff1a; 比较相邻的元素。如果第一个比第二个大&#xff0c;就交换他们两个。 对每一对相邻元素做同样的工作&#xf…

ComboBox基本用法

作用&#xff1a;是一个下拉框&#xff0c;用于以下拉列表的方式展示数据。 常用属性&#xff1a; 常用事件&#xff1a; 下拉列表框内容选择变化时触发 后台代码示范&#xff1a; private void comboBox1_SelectedIndexChanged(object sender, EventArgs e){//获取被选中的…

怎样优雅地增删查改(七):按用户查询

文章目录 实现使用测试 实现 定义按用户查询&#xff08;IUserOrientedFilter&#xff09;接口 public interface IUserOrientedFilter {public string EntityUserIdIdiom { get; }Guid? UserId { get; set; } }EntityUserIdIdiom&#xff1a;语义上的UserId&#xff0c;用于…

使用Pandas简化数据探索性分析

大家好&#xff0c;本文将探讨数据探索性分析的两个基本方面&#xff1a;数据集形状和空值。我们将深入了解Pandas如何简化这些任务&#xff0c;重点关注需要同时分析多个表格的情况。使用的库是pandas和tabulate。 数据集形状 要检索单个表格的形状&#xff0c;可以使用.sh…

「小摹AI」赋能原型设计 开放内测申请

「小摹AI」智能原型助手发布啦&#xff01; 4大AI应用能力&#xff1a;智能原型|智能文本|智能翻译|智能填充 释放原型设计的无限潜能 摹客AI - 让设计更具创造力http://www.mockplus.cn/ai/?hmsrwencsdnAI 智能原型 催生创新&#xff0c;开启原型设计新境界 根据描述&…

equals与Hashcde的区别

1、equals与hashCode的区别 equals与hashcode这两个方法都是从Object类中继承过来的。 hashCode()&#xff1a;计算出对象实例的哈希地址&#xff0c;并且返回该地址&#xff0c;称哈希函数&#xff0c;又称散列表。 equals()&#xff1a;反映的是对象的内存地址或者对象的内…

uniapp canvas 生成海报 小程序码 二维码

uniapp canvas 生成超简单海报带小程序码 canvas官网链接&#xff0c;可以先看下官方介绍&#xff0c;更好理解 uniapp官网canvas介绍 一、首先自定义一个生成海报的组件 uni-xcxcanvas.vue&#xff0c;创建同名目录 模板文件代码&#xff1a; <template><view&…

AtcoderABC251场

A - Six CharactersA - Six Characters 题目大意 给定一个由小写英文字母组成的字符串S&#xff0c;S的长度在1到3之间。 打印一个长度为6的字符串&#xff0c;该字符串是S的重复。 思路分析 通过将S重复拼接6次&#xff08;如果给定原字符串最小的情况&#xff09;&#xf…

【LLM】利用RoPE不微调大模型以扩展Context长度(更新中)

note 文章目录 note一、扩展LLM的Context长度1. 常见方法2. PCW方法 二、NBCE方法三、RoPE方法四、FlashAttention方法Reference 一、扩展LLM的Context长度 1. 常见方法 扩展LLM的Context长度其实已有不少&#xff0c;但多数是通过结合检索或者摘要的方式来缩短样本的长Conte…

深入学习 Redis - 常用数据类型,结构认识

目录 一、Redis数据类型 Redis 数据类型结构简单认识 每个数据类型具体的编码方式 1.string 2.hash 3.list 4.set 5.zset 典中典&#xff1a;记数字&#xff01;&#xff01;&#xff01; 6.查看 key 对应 value 的实际编码方式 如果本文有帮助到你&#xff0c;不…

古风编曲用什么软件?水果编曲FL Studio21怎么样

古风编曲需要什么乐器&#xff1f;古风编曲多采用笙、箫、二胡、古筝、琵琶、唢呐、二胡、竹笛、马头琴等中国传统乐器。古风编曲用什么软件&#xff1f;市面上几款热门软件有FL Studio、Cubase、Logic Pro等。 古风编曲需要什么乐器 我们常说的古风歌曲&#xff0c;其实是一…

CocoaPods could not find compatible versions for pod ““:

添加新的 SDK 依赖抛出了如下异常,无法找到可兼容的版本依赖库; [!] CocoaPods could not find compatible versions for pod "HDSSup":In Podfile:HDSSupSpecs satisfying the HDSSup dependency were found, but they required a higher minimum deployment targe…