当前位置: 首页 > news >正文

内存溢出、内存泄露的概述及常见情形

内存溢出(OutofMemoryError)

简述

java doc 中对 Out Of Memory Error 的解释是,没有空闲内存,并且垃圾收集器也无法提供更多内存。

JVM 提供的内存管理机制和自动垃圾回收极大的解放了用户对于内存的管理,由于 GC(垃圾回收)一直在发展,所有一般情况下,除非应用程序占用的内存增长速度非常快,造成垃圾回收已经跟不上内存消耗的速度,否则不太容易出现内存泄漏和内存溢出问题。但是基本不会出现并不等于不会出现,所以掌握 Java 内存模型原理和学会分析出现的内存溢出或内存泄漏仍然十分重要。

大多数情况下,GC 会进行各种年龄段的垃圾回收,实在不行了就放大招,来一次独占式的 Full GC 操作,这时候会回收大量的内存,供应用程序继续使用。

在抛出 OutofMemoryError 之前,通常垃圾收集器会被触发,尽其所能去清理出空间。例如:在引用机制分析中,涉及到 JVM 会去尝试回收软引用指向的对象等。在 java.nio.BIts.reserveMemory() 方法中,System.gc() 会被调用,以清理空间。

当然,也不是在任何情况下垃圾收集器都会被触发的。比如,分配了一个超大对象,类似一个超大数组超过堆的最大值,JVM 可以判断出垃圾收集并不能解决这个问题,所以直接抛出 OutofMemoryError。


内存溢出的常见情形

不同的内存溢出错误可能会发生在内存模型的不同区域,因此,需要根据出现错误的代码具体分析来找出可能导致错误发生的地方,并想办法进行解决。

  • 栈内存溢出(StackOverflowError)

    栈内存可以分为虚拟机栈(VM Stack)和本地方法栈(Native Method Stack),除了它们分别用于执行 Java 方法(字节码)和本地方法,其余部分原理是类似的。

    以虚拟机栈为例说明,Java 虚拟机栈是线程私有的,当线程中方法被调度时,虚拟机会创建用于保存局部变量表、操作数栈、动态连接和方法出口等信息的栈帧(Stack Frame)。

    具体来说,当线程执行某个方法时,JVM 会创建栈帧并压栈,此时刚压栈的栈帧就成为了当前栈帧。如果该方法进行递归调用时,JVM 每次都会将保存了当前方法数据的栈帧压栈,每次栈帧中的数据都是对当前方法数据的一份拷贝。如果递归的次数足够多,多到栈中栈帧所使用的内存超出了栈内存的最大容量,此时 JVM 就会抛出 StackOverflowError。

    总之,不论是因为栈帧太大还是栈内存太小,当新的栈帧内存无法被分配时,JVM 就会抛出 StackOverFlowError。

    优化方案:

    • 可以通过设置 JVM 启动参数 -Xss 参数来改变栈内存大小。

      注:分配给栈的内存并不是越大越好,因为栈内存越大,线程多,留给堆的空间就不多了,容易抛出OOM。JVM的默认参数一般情况没有问题(包括递归)。

    • 递归调用要控制好递归的层级,不要太高,超过栈的深度。

    • 递归调用要防止形成死循环,否则就会出现栈内存溢出。

  • 堆内存溢出(OutOfMemoryError:java heap space)

    堆内存的唯一作用就是存放数组和对象实例,即通过 new 指令创建的对象,包括数组和引用类型。

    堆内存溢出又分为两种情况:

    • Java 虚拟机的堆内存设置不够

      如果堆的大小不合理(没有显式指定 JVM 堆大小或者指定数值偏小),对象所需内存太大,创建对象时分配空间,JVM 就会抛出 OutOfMemoryError:java heap space 异常。

      优化方案:

      • 如果要处理比较可观的数据量,可以通过修改 JVM 启动参数 -Xms 、-Xmx 来调整。使用压力测试来调整这两个参数达到最优值。

      • 尽量避免大的对象的申请,例如文件上传,大批量从数据库中获取等。

        尽量分块或者分批处理,有助于系统的正常稳定的执行。

      • 尽量提高一次请求的执行速度,垃圾回收越早越好。

        否则,大量的并发来了的时候,再来新的请求就无法分配内存了,就容易造成系统的雪崩。

    • 堆内存泄露最终导致堆内存溢出

      当堆中一些对象不再被引用但垃圾回收器无法识别时,这些未使用的对象就会在堆内存空间中无限期存在,不断的堆积就会造成内存泄漏。不停的堆积最终会触发 java . lang.OutOfMemoryError。

      优化方案:如果发生了内存泄漏,则可以先找出导致泄漏发生的对象是如何被 GC ROOT 引用起来的,然后通过分析引用链找到发生泄漏的地方,进行代码优化。

  • 永久代溢出(OutOfMemoryError:PermGen sapce)

    对于老版本的 oracle JDK,因为永久代的大小是有限的,并且 JVM 对永久代垃圾回收(例如常量池回收、卸载不再需要的类型)非常不积极,所以当不断添加新类型的时候,永久代出现 OutOfMemoryError 也非常多见,尤其是在运行时存在大量动态类型生成的场合;类似 intern 字符串缓存占用太多空间,也会导致 OOM 问题,对应的异常信息,会标记出来和永久代相关:“java.lang.OutOfMemoryError:PermGen space"。

    随着元数据区的引入,方法区内存已经不再那么窘迫,所以相应的 OOM 有所改观,出现 OOM,异常信息则变成了:“java.lang.OutofMemoryError:Metaspace"。

  • 元空间内存溢出(OutOfMemoryError: Metaspace)

    元空间的溢出,系统会抛出 java.lang.OutOfMemoryError: Metaspace

    出现这个异常的问题的原因是系统的代码非常多或引用的第三方包非常多或者通过动态代码生成类加载等方法,导致元空间的内存占用很大。

    优化方案:

    • 默认情况下,元空间的大小仅受本地内存限制。

      但是为了整机的性能,尽量还是要对该项进行设置,优化参数配置,以免造成整机的服务停机。

    • 慎重引用第三方包

      对第三方包,一定要慎重选择,不需要的包就去掉。

      这样既有助于提高编译打包的速度,也有助于提高远程部署的速度。

    • 关注动态生成类的框架

      对于使用大量动态生成类的框架,要做好压力测试,验证动态生成的类是否超出内存的需求会抛出异常。

  • 直接内存溢出

    如果直接或间接(很多 java NIO,例如在 netty 的框架中被封装为其他的方法)使用了 ByteBuffer 中的 allocateDirect() 方法,而又不做 clear 的时候,就会抛出 java.lang.OutOfMemoryError: Direct buffer memory 异常。

    如果经常有类似的操作,可以考虑设置 JVM 参数:-XX:MaxDirectMemorySize,并及时 clear 内存。

  • 创建本地线程内存溢出

    除了堆以外的区域,无法为线程分配一块内存区域了(线程基本只占用堆以外的内存区域),要么是内存本身就不够,要么堆的空间设置得太大了,导致了剩余的内存已经不多了,而由于线程本身要占用内存,所以就不够用了。

    优化方案:

    • 首先检查操作系统是否有线程数的限制,如果使用 shell 也无法创建线程,就需要调整系统的最大可支持的文件数。
    • 日常开发中尽量保证线程最大数的可控制的,不要随意使用可以无限制增长的线程池。
  • 数组超限内存溢出

    JVM 在为数组分配内存之前,会执行特定平台的检查:分配的数据结构是否在此平台是可寻址的。

    一般来说 java 对应用程序所能分配数组最大大小是有限制的,只不过不同的平台限制有所不同,但通常在1到21亿个元素之间。当应用程序试图分配大于 Java 虚拟机可以支持的数组时会报 Requested array size exceeds VM limit 错误。

    不过这个错误一般少见的,主要是由于 Java 数组的索引是 int 类型。 Java 中的最大正整数为 2 ^ 31 - 1 = 2,147,483,647。 并且平台特定的限制可以非常接近这个数字,例如:Jdk1.8 可以初始化数组的长度高达 2,147,483,645(Integer.MAX_VALUE-2)。若是在将数组的长度再增加 1 达到 nteger.MAX_VALUE-1 ,就会出现 OutOfMemoryError 了。

    优化方案:数组长度要在平台允许的长度范围之内。

  • 超出交换区内存溢出

    在 Java 应用程序启动过程中,可以通过 -Xmx 和其他类似的启动参数限制指定的所需的内存。而当 JVM 所请求的总内存大于可用物理内存的情况下,操作系统开始将内容从内存转换为硬盘。

    当应用程序向 JVM native heap 请求分配内存失败并且 native heap 也即将耗尽时, JVM 会抛出Out of swap space 错误, 错误消息中包含分配失败的大小(以字节为单位)和请求失败的原因。

    优化方案:

    • 增加系统交换区的大小。

      但如果使用了交换区,性能会大大降低,不建议采用这种方式。

      生产环境尽量避免最大内存超过系统的物理内存。其次,去掉系统交换区,只使用系统的内存,保证应用的性能。

  • 系统杀死进程内存溢出

    操作系统是建立在进程的概念之上,这些进程在内核中作业,其中有一个非常特殊的进程,称为“内存杀手(Out of memory killer)”。当内核检测到系统内存不足时,OOM killer 被激活,检查当前谁占用内存最多然后将该进程杀掉。

    一般 Out of memory:Kill process or sacrifice child 报错会在当可用虚拟内存(包括交换空间)消耗到让整个操作系统面临风险内存不足时,会被触发。在这种情况下,OOM Killer 会选择“流氓进程”并杀死它。

    优化方案:

    • 增加交换空间的方式可以缓解 Java heap space 异常
    • 但还是建议最好的方案就是升级系统内存,让 java 应用有足够的内存可用,就不会出现这种问题。

内存泄漏(memory leak)

简述

  • 也称作“存储渗漏”。

  • 严格来说,只有对象不会再被程序用到了,但是 GC 又不能回收它们的情况,才叫内存泄漏。

    但实际情况很多时候一些不太好的实践(或疏忽)会导致对象的生命周期变得很长甚至导致 OOM,也可以叫做宽泛意义上的“内存泄漏”。

  • 尽管内存泄漏并不会立刻引起程序崩溃,但是一旦发生内存泄漏,程序中的可用内存就会被逐步蚕食,直至耗尽所有内存,最终出现 OutOfMemory 异常,导致程序崩溃。

    注意:这里的可用内存并不是指物理内存,而是指虚拟内存大小,这个虚拟内存大小取决于磁盘交换区设定的大小。

  • Java 使用可达性分析算法,最上面的数据不可达,就是需要被回收的。

    后期有一些对象不用了,按道理应该断开引用,但是存在一些链没有断开,从而导致没有办法被回收


可达性分析算法

可达性分析算法:判断对象是否是不再使用的对象,本质都是判断一个对象是否还被引用。那么对于这种情况下,由于代码的实现不同就会出现很多种内存泄漏问题(让 JVM 误以为此对象还在引用中,无法回收,造成内存泄漏)。

举例说明:

  • 对象 X 引用对象 Y,X 的生命周期比 Y 的生命周期长;
  • 那么当 Y 生命周期结束的时候,X 依然引用着 Y,这时候,垃圾回收期是不会回收对象 Y 的;
  • 如果对象 X 还引用着生命周期比较短的 A、B、C,对象 A 又引用着对象 a、b、c,这样就可能造成大量无用的对象不能被回收,进而占据了内存资源,造成内存泄漏,直到内存溢出。

在这里插入图片描述


Java 中内存泄漏的 8 种情况

  1. 静态集合类,如 HashMap、LinkedList 等等。

    如果这些容器为静态的,那么它们的生命周期与 JVM 程序一致,则容器中的对象在程序结束之前将不能被释放,从而造成内存泄漏。

    简而言之,长生命周期的对象持有短生命周期对象的引用,尽管短生命周期的对象不再使用,但是因为长生命周期对象持有它的引用而导致不能被回收。

  2. 单例模式

    单例模式,和静态集合导致内存泄露的原因类似,因为单例的静态特性,它的生命周期和 JVM 的生命周期一样长,所以如果单例对象如果持有外部对象的引用,那么这个外部对象也不会被回收,那么就会造成内存泄漏。

  3. 内部类持有外部类的引用

    在 Java 中内部类的定义与使用一般为成员内部类与匿名内部类,他们的对象都会隐式持有外部类对象的引用,影响外部类对象的回收。

    可以通过反编译可以来验证这个理论:

    • java 代码

      public class Outer {private String name;class Inner{private String test;}
      }
      
    • 反编译后的代码

      class Outer$Inner {private String test;final Outer this$0;Outer$Inner() {this.this$0 = Outer.this;super();}
      }
      

      可以清楚的发现,内部类的属性中有这个外部类,并且在内部类的构造函数中有这个外部类属性的初始化。

    如果一个外部类的实例对象的方法返回了一个内部类的实例对象,而这个内部类对象被长期引用了,那么即使那个外部类实例对象不再被使用,但由于内部类持有外部类的实例对象引用,这个外部类对象将不会被垃圾回收,这也会造成内存泄漏。

  4. 各种连接,如数据库连接、网络连接和 IO 连接等

    在对数据库进行操作的过程中,首先需要建立与数据库的连接,当不再使用时,需要调用 close 方法来释放与数据库的连接。只有连接被关闭后,垃圾回收器才会回收对应的对象。

    否则,如果在访问数据库的过程中,**对 Connection、Statement 或 ResultSet 不显性地关闭,将会造成大量的对象无法被回收,**从而引起内存泄漏。

  5. 变量不合理的作用域

    一般而言,一个变量的定义的作用范围大于其使用范围,很有可能会造成内存泄漏。另一方面,如果没有及时地把对象设置为 null,很有可能导致内存泄漏的发生。

    class Outer$Inner {private String test;final Outer this$0;Outer$Inner() {this.this$0 = Outer.this;super();}
    }
    

    如上面这个伪代码,通过 readFromNet 方法把接受的消息保存在变量 msg 中,然后调用 saveDB 方法把 msg 的内容保存到数据库中,此时 msg 已经就没用了,由于 msg 的生命周期与对象的生命周期相同,此时 msg 还不能回收,因此造成了内存泄漏。

    优化方案:

    • 方案1:这个 msg 变量可以放在方法内部,当方法使用完,那么 msg 的生命周期也就结束,就可以回收了。
    • 方案2:在使用完 msg 后,把 msg 设置为 null,这样垃圾回收器也会回收 msg 的内存空间。
  6. 改变哈希值

    当一个对象被存储进 HashSet 集合中以后,就不能修改这个对象中的那些参与计算哈希值的字段了。

    否则,对象修改后的哈希值与最初存储进 HashSet 集合中时的哈希值就不同了,在这种情况下,即使在 contains 方法使用该对象的当前引用作为的参数去 HashSet 集合中检索对象,也将返回找不到对象的结果,这也会导致无法从 HashSet 集合中单独删除当前对象,造成内存泄漏。

    这也是 String 为什么被设置成了不可变类型,可以放心地把 String 存入 HashSet,或者把 String 当做 HashMap 的 key 值;

    当想把自己定义的类保存到散列表的时候,需要保证对象的 hashCode 不可变。

    /*** 演示内存泄漏*/
    public class ChangeHashCode1 {public static void main(String[] args) {HashSet hs = new HashSet();Point cc = new Point();cc.setX(10);//hashCode = 41hs.add(cc);cc.setX(20);//hashCode = 51System.out.println("hs.remove = " + hs.remove(cc));//falsehs.add(cc);System.out.println("hs.size = " + hs.size());//size = 2}
    }class Point {int x;public int getX() return x;public void setX(int x) this.x = x;@Overridepublic int hashCode() {final int prime = 31;int result = 1;result = prime * result + x;return result;}@Overridepublic boolean equals(Object obj) {if (this == obj) return true;if (obj == null) return false;if (getClass() != obj.getClass()) return false;Point other = (Point) obj;if (x != other.x) return false;return true;}
    }
    
  7. 对象缓存泄漏

    一旦把对象引用放入到缓存中,就很容易遗忘。

    比如:代码中会加载一个表中的数据到缓存(内存)中,测试环境只有几百条数据,但是生产环境则可能会有几百万的数据。

    优化方案:可以使用 WeakHashMap 代表缓存,此种 Map 的特点是,当除了自身有对 key 的引用外,此 key 没有其他引用那么此 map 会自动丢弃此值。

    /*** 演示内存泄漏*/
    public class MapTest {static Map wMap = new WeakHashMap();static Map map = new HashMap();public static void main(String[] args) {init();testWeakHashMap();testHashMap();}public static void init() {String ref1 = new String("obejct1");String ref2 = new String("obejct2");String ref3 = new String("obejct3");String ref4 = new String("obejct4");wMap.put(ref1, "cacheObject1");wMap.put(ref2, "cacheObject2");map.put(ref3, "cacheObject3");map.put(ref4, "cacheObject4");System.out.println("String引用ref1,ref2,ref3,ref4 消失");}public static void testWeakHashMap() {System.out.println("WeakHashMap GC之前");for (Object o : wMap.entrySet()) {System.out.println(o);}try {System.gc();TimeUnit.SECONDS.sleep(5);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("WeakHashMap GC之后");for (Object o : wMap.entrySet()) {System.out.println(o);}}public static void testHashMap() {System.out.println("HashMap GC之前");for (Object o : map.entrySet()) {System.out.println(o);}try {System.gc();TimeUnit.SECONDS.sleep(5);} catch (InterruptedException e) {e.printStackTrace();}System.out.println("HashMap GC之后");for (Object o : map.entrySet()) {System.out.println(o);}}}
    /*** 结果* String引用ref1,ref2,ref3,ref4 消失* WeakHashMap GC之前* obejct2=cacheObject2* obejct1=cacheObject1* WeakHashMap GC之后* HashMap GC之前* obejct4=cacheObject4* obejct3=cacheObject3* Disconnected from the target VM, address: '127.0.0.1:51628', transport: 'socket'* HashMap GC之后* obejct4=cacheObject4* obejct3=cacheObject3**/
    

    上面代码演示 WeakHashMap 如何自动释放缓存对象:当 init 函数执行完成后,局部变量字符串引用 weakd1,weakd2,d1,d2 都会消失,此时只有静态 map 中保存中对字符串对象的引用,可以看到,调用 gc 之后,HashMap 的没有被回收,而 WeakHashMap 里面的缓存被回收了。

  8. 监听器和回调

    内存泄漏另一个常见来源是监听器和其他回调,如果客户端在实现的 API 中注册回调,却没有显式的取消,那么就会积聚。

    需要确保回调立即被当作垃圾回收的最佳方法是只保存它的弱引用,例如将它们保存成为 WeakHashMap 中的键。

相关文章:

内存溢出、内存泄露的概述及常见情形

内存溢出(OutofMemoryError) 简述 java doc 中对 Out Of Memory Error 的解释是,没有空闲内存,并且垃圾收集器也无法提供更多内存。 JVM 提供的内存管理机制和自动垃圾回收极大的解放了用户对于内存的管理,由于 GC&…...

Linux 中断实验

目录 一、Linux 中断简介 上半部与下半部 二、添加设备树 三、编写驱动 1、定义宏 2、编写一个key结构体 3、imx6uirq设备添加成员 ​编辑4、按键中断处理函数 5、按键初始化 6、在驱动入口添加初始化 7、 驱动出口函数 代码如下 四、利用定时器进行消抖处理 1、添…...

【c++】指针

文章目录指针的定义和使用指针所占的内存空间空指针野指针const修饰指针指针和数组指针和函数指针、数组、函数案例:冒泡排序指针的定义和使用 指针定义的语法:数据类型 * 指针变量名 使用指针: 可以通过解引用的方式来找到指针指向的内存&…...

别具一格的婚礼,VR全景+婚礼的优势展现在哪里?

随着90后、95后逐渐步入结婚的主力军中,如何策划一场别具一格的婚礼是许多年轻人所头疼的,那么今年我们就可以玩点新潮的,VR婚礼或许是个不错的选择。 VR全景婚礼就是通过全景摄像机对婚礼进行记录,不但可以帮助新人捕捉婚礼的精彩…...

【GD32F427开发板试用】5. SPI驱动TFTLCD屏幕

本篇文章来自极术社区与兆易创新组织的GD32F427开发板评测活动,更多开发板试用活动请关注极术社区网站。作者:hehung 之前发帖 【GD32F427开发板试用】1. 串口实现scanf输入控制LED 【GD32F427开发板试用】2. RT-Thread标准版移植 【GD32F427开发板试用…...

测试2年还拿实习生的薪资打发我,你后悔去吧····

20年7月大学毕业,学的计算机科学专业。因为考研之后,秋招结束了。没什么更多的岗位选择,就想找个工作先干着,然后亲戚在一家大厂公司上班说要招测试,所以就来做测试了。 虽然都是属于计算机大类,但自己专业…...

面向对象程序(C++)设计基础

一、类&对象C 在 C 语言的基础上增加了面向对象编程,C 支持面向对象程序设计。类是 C 的核心特性,通常被称为用户定义的类型。类提供了对象的蓝图,所以基本上,对象是根据类来创建的。声明类的对象,就像声明基本类型…...

conda安装nodejs版本过低解决方法

conda命令直接安装nodejs时,可能会由于镜像源中nodejs版本过低导致没法安装高本版的nodejs,导致无法jupyterlab使用一些扩展插件。 解决方法如下:(windows环境下直接按提示下载版本安装就行,此处只介绍linux环境的解决…...

前端工程师leetcode算法面试必备-二分搜索算法(下)索算法(下)

一、287. 寻找重复数 给定一个包含 n 1 个整数的数组 nums,其数字都在 1 到 n 之间(包括 1 和 n),可知至少存在一个重复的整数。假设只有一个重复的整数,找出这个重复的数。 1、HashMap 在没有其它附加条件的情况下&…...

使用Autowired为什么会被IDEA警告,应该怎么修改最佳

问题原因 关于这个问题,其实答案相对统一,实际上用大白话说起来也容易理解。 初始化问题 先看一下Java初始化类的顺序:父类的静态字段 > 父类静态代码块 > 子类静态字段 > 子类静态代码块 > 父类成员变量 > 父类构造代码块 &…...

面向对象(中)

面向对象(中) 一、 面向对象之继承性 继承性的好处 减少代码的冗余,提高了代码的复用性。 便于功能的扩展。 为多态性的使用,提供了前提。 继承性的格式 class A extends B{} A:子类、派生类、subclass B&#xff1a…...

【云原生】promehtheus整合grafana实现可视化监控实战

文章目录前言一. 实验环境二. 安装grafana2.1 grafana的介绍2.2 为什么选择grafana?2.3 grafana下载及安装三. 网页端配置grafana3.1 浏览器访问grafana网页3.2 使用grafana 获取prometheus的数据源3.3 grafana导入prometheus模板总结前言 大家好,又见面…...

Linux 内核定时器实验

目录 一、内核时间管理简介 二、内核定时器简介 三、驱动编写 1、修改makefile 2、添加定义 3、初始化led函数 4、添加调用 5、初始化定时器与定时器处理函数 这部分代码如下 四、ioctl函数 五、内核添加unlocked_ioctl 函数 1、添加设备操作集unlocked_ioctl成员 2…...

喜欢大屏电视?那就选择酷开系统,实现智能生活享受

随着科技的发展和我们生活水平的提高,越来越多的消费者开始认可并习惯使用各种高质量的科技产品,比如喜欢玩游戏的消费者,他们往往会追求流畅性更强、刷新率更快的大显示屏,以此获得更真实刺激的游戏体验,而喜欢追剧的…...

PMP应该如何备考?

备考之初的我们,总会四处搜索PMP备考经验,希望能拿到那些高分通关前辈的备考经验和方法。众所周知PMP考试因为有35个学时培训的基本要求,所以肯定是要通过培训机构报名的。 一,首先我们需要了解到新的考纲 1.PMP模块划分发生变化…...

AcWing《蓝桥杯集训·每日一题》—— 3956.截断数组

AcWing《蓝桥杯集训每日一题》—— 3956. 截断数组 文章目录AcWing《蓝桥杯集训每日一题》—— 3956. 截断数组一、题目二、解题思路三、代码实现本次博客我是通过Notion软件写的,转md文件可能不太美观,大家可以去我的博客中查看:北天的 BLOG…...

Docker的数据管理

一、管理docker容器中数据 管理Docker 容器中数据主要有两种方式:数据卷(Data Volumes)和数据卷容器( DataVolumes Containers) 。 1、 数据卷 数据卷是一个供容器使用的特殊目录,位于容器中。可将宿主机的目录挂载到数据卷上,对数据卷的修改操作立刻…...

RxJS处理异步数据流

什么是异步? 异步(Asynchronous)指的是不同步发生的事件或操作。通常,同步操作是指一系列代码按照顺序依次执行,直到当前代码块执行完毕后才继续执行下一个代码块;而异步操作则是指某些代码会被提交到后台执行&#…...

IP地址与用户行为

IP地址能够解决网络风险和提高网络安全的原因是:所有的网络请求都会带有IP信息,是访问者的独立标识,另外ip地址的分配和管理比较严格,难以造假。另外ip属于网络层,可以轻松的对其进行阻断。现有的各种网络安全、负载均…...

底层逻辑2

有些创业者,在3D打印⽕爆的时候做3D打印,在VR(虚拟现 实)蓬勃发展的时候转⾏做VR,在区块链成为热⻔话题的时候摇身⼀ 变成了区块链专家,⽽⼈⼯智能⽕了以后,他们⼜全身⼼投⼊⼈⼯智 能这⼀⾏。再…...

RocketMQ延迟消息机制

两种延迟消息 RocketMQ中提供了两种延迟消息机制 指定固定的延迟级别 通过在Message中设定一个MessageDelayLevel参数,对应18个预设的延迟级别指定时间点的延迟级别 通过在Message中设定一个DeliverTimeMS指定一个Long类型表示的具体时间点。到了时间点后&#xf…...

uni-app学习笔记二十二---使用vite.config.js全局导入常用依赖

在前面的练习中,每个页面需要使用ref,onShow等生命周期钩子函数时都需要像下面这样导入 import {onMounted, ref} from "vue" 如果不想每个页面都导入,需要使用node.js命令npm安装unplugin-auto-import npm install unplugin-au…...

ServerTrust 并非唯一

NSURLAuthenticationMethodServerTrust 只是 authenticationMethod 的冰山一角 要理解 NSURLAuthenticationMethodServerTrust, 首先要明白它只是 authenticationMethod 的选项之一, 并非唯一 1 先厘清概念 点说明authenticationMethodURLAuthenticationChallenge.protectionS…...

k8s业务程序联调工具-KtConnect

概述 原理 工具作用是建立了一个从本地到集群的单向VPN,根据VPN原理,打通两个内网必然需要借助一个公共中继节点,ktconnect工具巧妙的利用k8s原生的portforward能力,简化了建立连接的过程,apiserver间接起到了中继节…...

3-11单元格区域边界定位(End属性)学习笔记

返回一个Range 对象,只读。该对象代表包含源区域的区域上端下端左端右端的最后一个单元格。等同于按键 End 向上键(End(xlUp))、End向下键(End(xlDown))、End向左键(End(xlToLeft)End向右键(End(xlToRight)) 注意:它移动的位置必须是相连的有内容的单元格…...

[免费]微信小程序问卷调查系统(SpringBoot后端+Vue管理端)【论文+源码+SQL脚本】

大家好,我是java1234_小锋老师,看到一个不错的微信小程序问卷调查系统(SpringBoot后端Vue管理端)【论文源码SQL脚本】,分享下哈。 项目视频演示 【免费】微信小程序问卷调查系统(SpringBoot后端Vue管理端) Java毕业设计_哔哩哔哩_bilibili 项…...

腾讯云V3签名

想要接入腾讯云的Api,必然先按其文档计算出所要求的签名。 之前也调用过腾讯云的接口,但总是卡在签名这一步,最后放弃选择SDK,这次终于自己代码实现。 可能腾讯云翻新了接口文档,现在阅读起来,清晰了很多&…...

c# 局部函数 定义、功能与示例

C# 局部函数:定义、功能与示例 1. 定义与功能 局部函数(Local Function)是嵌套在另一个方法内部的私有方法,仅在包含它的方法内可见。 • 作用:封装仅用于当前方法的逻辑,避免污染类作用域,提升…...

Python实现简单音频数据压缩与解压算法

Python实现简单音频数据压缩与解压算法 引言 在音频数据处理中,压缩算法是降低存储成本和传输效率的关键技术。Python作为一门灵活且功能强大的编程语言,提供了丰富的库和工具来实现音频数据的压缩与解压。本文将通过一个简单的音频数据压缩与解压算法…...

算术操作符与类型转换:从基础到精通

目录 前言:从基础到实践——探索运算符与类型转换的奥秘 算术操作符超级详解 算术操作符:、-、*、/、% 赋值操作符:和复合赋值 单⽬操作符:、--、、- 前言:从基础到实践——探索运算符与类型转换的奥秘 在先前的文…...