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

【JVM系列】- 穿插·对象的实例化与直接内存

对象的实例化与直接内存

😄生命不息,写作不止
🔥 继续踏上学习之路,学之分享笔记
👊 总有一天我也能像各位大佬一样
🌝分享学习心得,欢迎指正,大家一起学习成长!

在这里插入图片描述

文章目录

  • 对象的实例化与直接内存
    • 创建对象的方式
      • ① 使用new关键字
      • ② 通过反射机制
      • ③ 使用克隆的方式
      • ④ 反序列化
    • 创建对象的步骤
      • ① 判断对象对应的类是否类加载
      • ② 为对象分配内存
      • ③ 处理并发安全问题
      • ④ 初始化
      • ⑤ 设置对象的对象头
      • ⑥ 执行init方法进行初始化
    • *对象的布局
      • 1). 对象头(Object Header)
      • 2). 实例数据(Instance Data)
      • 3). 对齐填充(Padding)
      • 案例理解
    • 对象的访问定位
      • 对象访问的两种方式
        • 1). 句柄访问
        • 2). 指针访问(Hotspot采用此方法)
    • 直接内存(Direct Memory)
      • 直接内存概述
      • 直接内存的性能
      • 直接内存的OOM
    • 总结

在Java中,对象实例化是创建一个类的实例的过程。

实例化(instantiate)是指在面向对象的编程中,把用类创建对象的过程称为实例化。是将一个抽象的概念类,具体到该类实物的过程。实例化过程中一般由**类名 对象名 = new 类名(参数1,参数2…参数n)**构成。

创建对象的方式

在Java中,创建对象的方式有许多种,简单的概括都有哪些方法。

① 使用new关键字

使用new 来创建方法是最常见的一种创建方式,这种方法会调用构造方法(默认是无参构造方法),如果有自定义构造方法,就会使用自定义构造方法来创建对象。

MyClass myObject = new MyClass();

还有一种常见的方式,就是使用类的静态方法,这种方式,实际上在静态方法内部也是使用了new的方式来创建,这里可以是无参构造也可以是自定义的含参构造器。
还有一种也是new方式的变形,就是通过一个专门的工厂类或者静态方法来创建对象。

MyClass myObject = MyClassFactory.createMyClass();

② 通过反射机制

使用 Java 的反射机制,可以在运行时获取类的信息并创建对象。但是这种方式只能是使用空参的构造器,权限还必须是public。

Class<?> myClass = Class.forName("com.example.MyClass");
MyClass myObject = (MyClass) myClass.newInstance();

在Java9之后就不推荐使用了,可以选择使用Constructor的newInstance(xx)。clazz.getDeclaredConstructor().newInstance(),这个也是反射的方式,可以调用空参、带参的构造器,对于权限没有要求。

③ 使用克隆的方式

通过实现 Cloneable 接口并覆盖 clone 方法,可以创建对象的副本。这种方式不调用任何构造器。

MyClass originalObject = new MyClass();
MyClass clonedObject = (MyClass) originalObject.clone();

④ 反序列化

反序列化是将对象从其序列化形式转换回原始对象的过程。在Java中,对象可以通过序列化将其状态保存到文件或通过网络传输。反序列化则是从这些序列化的数据中重新构建对象。

除了以上方法,还有其他的创建方式,比如三方库等。

创建对象的步骤

我们通过字节码来看一下实例化对象的过程。
在这里插入图片描述

对于上图中的Object s = new Object();,首先我们可以将其分成三个部分来看,第一个部分Object,这个是存放在方法区中的,也就是存储着类的信息、常量池、静态变量等等;第二部分就是s,这个是存在Java栈中,这是个引用对象,在栈中的本地变量表中存放对象的引用地址,指向Java的对象实例数据;而第三部分new Object(),这是对象的实例数据,存在Java堆中。
接下来分析一下字节码

// new创建一个对象,#2是常量池中对应 java/lang/Object 类的索引
0 new #2 <java/lang/Object>
// dup是复制栈顶元素。在这里,复制了刚刚创建的新对象的引用。
3 dup
// 调用对象的构造方法。#1 是常量池中对应 <init> 构造方法的索引,V 表示无返回值。这里实际上调用了 java/lang/Object 类的构造方法,对新创建的对象进行初始化。
4 invokespecial #1 <java/lang/Object.<init> : ()V>
// 将栈顶元素(即新创建的对象的引用)存储到本地变量1中。
7 astore_1
// 返回。这里返回的是 void 类型,因为在 Java 中构造方法没有显式的返回值。
8 return

以上是从字节码的过程,接下来用执行过程来介绍,以下分为6个步骤来。

① 判断对象对应的类是否类加载

首先,要实例化一个对象,必须加载其对应的类。类加载是Java程序启动的一部分。当程序首次引用一个类时,类加载器负责加载这个类的字节码到内存中。这就是加载类。类加载的下一个阶段是链接。在链接过程中,将为类的静态变量分配存储空间,并且如果存在父类,还会链接到父类。链接阶段将符号引用转化为直接引用。在链接中还有验证、准备、解析。 在类的初始化阶段,执行类构造器 方法。这是一个特殊的静态方法,由编译器生成,包含类的静态字段的初始化和静态代码块的执行。初始化是按需进行的,即只有在首次实例化类的对象或者首次访问类的静态成员时才会触发。如果一个类有父类,那么会首先初始化父类。

这个部分在之前的文章《类加载子系统与加载过程》就有描述过,这里就是简单复述一下。回归正传,当虚拟机遇到一条new指令的时候,首先就会先去检查这条指令的参数能否在Metaspace的常量池中,定位到一个类的符号引用(就如以上字节码中的0 new #2 <java/lang/Object>这行字节码,#2就是这个Object对象的符号引用),并且会检查符号引用对应的类是否已经被加载、解析和初始化。如果没有,将会重新类加载,会在双亲委派模式下,使用类加载器去查找对应的.class文件。如果没有找到就会抛出ClassNotFoundException异常。

② 为对象分配内存

一旦类初始化完成,JVM 就会为对象分配内存。内存分配的方式可以是在堆上分配,也可能是栈上分配,具体取决于对象的生命周期和大小。
再分配内存,首先需要计算对象占用的空间大小,接着就是在堆中划分一块内存给新对象,如果实例化成员变量是引用变量,仅分配引用变量空间即可,即4/8个字节大小。

关于字节大小,如果操作系统是64位
boolean:占1个字节、byte:占1个字节
char:占2个字节、short:占2个字节
int:占4个字节、float:占4个字节
long:占8个字节、double:占8个字节
引用变量:占8个字节

对于对象内存的分配,还需要看内存是否规整。
如果内存是规整的,那么JVM将采用的是指针碰撞(Pointer Bumping)[1]来为对象分配内存。

什么是指针碰撞?
指针碰撞(Pointer Bumping)是一种内存分配和垃圾回收的实现方式,通常用于实现可移植的、线程安全的垃圾回收器。它的工作原理是通过移动指针来分配和回收内存。在使用指针碰撞时,整个可用的内存被看作一个大的连续块。实际上意思就是将所有使用过的内存放在一边,空闲的内存存在另一边,中间放着一个指针作为分界点的指示器,分配内存的话,就是把指针向空闲内存挪动一段与对象大小相同的距离。如果垃圾收集器是选择Serial、ParNew这种基于压缩算法,虚拟机采用这种分配方式,一般使用带有compact(整理)过程的收集器是,使用指针碰撞。

然而,如果内存是不规整的,也就是说用过的和没用过的内存相互交错,虚拟机就会采用空闲列表法来为对象分配内存,也就是虚拟机就需要维护一个列表,记录了哪些内存块是可用的,再分配的时候会从列表中去找到一块足够大的空间去划分对象实例,并更新列表上的内容,这种的分配方式就是空闲列表(Free List)。

选择哪种分配方式是由Java堆是否规整决定的,而Java堆是否规整又由所采用的垃圾收集器是否带有压缩整理功能来决定。

③ 处理并发安全问题

在JVM创建对象的过程中,是会涉及一些并发安全问题,并且也有一些解决策略。

  • 采用CAS失败重试、区域加锁保证原子性
    • 类加载是多线程环境下的一个关键问题。JVM使用类加载锁(Class Loading Lock)来保证在同一时刻只有一个线程能够加载一个类。这个锁是全局锁,确保每个类在同一时刻只能被一个线程加载。
  • 为每个线程都预分配一块TLAB
    • 通过-XX:+/-UserTLAB参数设定

④ 初始化

初始化分配到的空间就是最开始的默认初始化进行默认值设置,这能保证对象实例字段在不赋值时就可以直接使用。

属性赋值的操作有几部分,首先是属性的默认初始化,接着就是显示初始化、代码块中的初始化,然后是由构造器进行初始化。

⑤ 设置对象的对象头

在这一步就会将对象的所属类(元数据信息)、对象的HashCode和对象的GC信息、锁信息等数据存储到对象的对象头中,这个过程的具体设置方式取决于JVM实现。

⑥ 执行init方法进行初始化

在Java程序的视角来看,初始化才是正式开始,初始化成员变量,执行实例化代码块,调用类的构造方法,并把堆内对象的首地址赋值给引用变量。这一部分就是将对象属性进行显示初始化、代码块中的初始化、构造器的初始化。

那么怎样才算对象创建完成呢?实际上,对象的创建从经历了加载类元信息,为对象分配内存,处理并发问题,属性的默认初始化,设置对象头的信息,数据的显示初始化、代码中初始化以及构造器初始化的几个过程之后才算对象已经创建完成,当然,如果说对象在默认初始化完毕就算创建完成也是可以的。

*对象的布局

在Hotspot 虚拟机中,对象在内存中的存储布局,可以分为三个区域:对象头(Object Header)、实例数据(Instance Data)、对齐填充(Padding)。在对象头中包含了标记字(mark word)、类指针(klass word)和 数组长度(array length)。synchronized主要是跟对象头有关系,也就是通过mark word的字节位数来表示各种锁状态。
未命名文件 (17).png

关于锁的知识点之前在《【多线程与高并发】- synchronized锁的认知》就已经介绍过了。

1). 对象头(Object Header)

在HotSpot虚拟机中,Java对象的头部包含了一些用于管理对象的元数据信息。其中主要是包含以下两个部分。

  • Mark Word(标记字): 占用 8 字节,包含了对象的一些状态信息,比如哈希值、锁状态标志、线程持有的锁、线程ID、偏向锁时间戳、GC 分代年龄等。Mark Word 的内容在对象的生命周期中可能会发生变化。
  • klass word(类型指针):Class对象的类型指针, 占用 4 字节或 8 字节,Jdk1.8默认开启指针压缩后为4字节,关闭指针压缩(-XX:-UseCompressedOops)后,长度为8字节1。其指向的位置是对象对应的Class对象(其对应的元数据对象)的内存地址1。

如果是数组的话,还需要记录数组的长度。

2). 实例数据(Instance Data)

这是对象真正存储的有效信息,包括程序代码中定义的各种类型的字段(也包括了继承父类的和自身的字段)。如果存储的数组对象,会包含一个用于记录数组长度的字段以及存储了实际数组元素的部分。JVM会根据对象的布局灵活地调整内存布局,减小对象头和实例数据的总体大小,从而降低内存占用。对于相同宽度的字段会被分配到一起,父类定义的变量会出现在子类之前,如果CompactFields参数为true(也是默认值),子类的窄变量可能插入父类的变量空隙。

实例数据主要包括对象的各种成员变量,包括基本类型和引用类型。基本类型直接存储内容,引用类型则是存储的指针,static类型的变量会放到类中,而不是放到实例数据里。

3). 对齐填充(Padding)

对齐填充并不是必须的,这是一种优化的概念,是作为一种占位符的作用。主要是为了满足硬件对齐的要求,提高访问效率和性能。通过插入一些额外的字节,使得对象的起始地址符合特定的对齐要求。这样可以确保对象的实例数据按照硬件对齐规则排列,从而提高内存访问的效率。

案例理解

这里我准备一个案例,在Customer类中设置了几个变量,并继承父类User,其中有一个引用变量Account类。通过Start#main()来实现本次的案例。

// 父类
public class User {String username;
}
// 子类
public class Customer extends User {int id = 1;String name;Account account;{name = "默认客户";}public Customer() {account = new Account();}
}
// 引用的类
public class Account {int ids;double money;String tab;
}
public class Start {public static void main(String[] args) {Customer customer = new Customer();/*java对象的内存布局以及使用ClassLayout查看布局*/System.out.println("Customer:" + ClassLayout.parseInstance(customer).toPrintable());    }
}

这里我引入了ClassLayout来查看Java对象内存布局的,需要引入以下坐标。

<!--  java对象的内存布局以及使用ClassLayout查看布局  -->
<dependency><groupId>org.openjdk.jol</groupId><artifactId>jol-core</artifactId><version>0.17</version>
</dependency>

通过运行Start#main()可以清晰看到所占用的字节信息,对于Customer对象,继承了User类,在创建实例的时候会把父类的属性也一并加载过来。首先,对象头是固定的8(标记字)+4(类型指针)字节,实例数据由于会加载父类属性,一共是16字节(对于引用类型,JVM是64位应该是占8字节,但是采用了指针压缩,所以只占了4字节),8+4+16=28字节,不满足对齐要求,因此还需要引入对齐填充占4个字节,一共就是32字节。

Customercom.lyd.testboot.jvm.objectdemo.Customer object internals:
OFF  SZ                                      TYPE DESCRIPTION               VALUE0   8                                           (object header: mark)     0x0000000000000001 (non-biasable; age: 0)8   4                                           (object header: class)    0xf800c18212   4                          java.lang.String User.username             null16   4                                       int Customer.id               120   4                          java.lang.String Customer.name             (object)24   4   com.lyd.testboot.jvm.objectdemo.Account Customer.account          (object)28   4                                           (object alignment gap)    
Instance size: 32 bytes
Space losses: 0 bytes internal + 4 bytes external = 4 bytes total

从以上打印出来的日志能够看到实例中包含了父类与本类的属性以及所占字节数。下图就来介绍整个对象的实例过程。
在这里插入图片描述

每个方法就是一个栈帧,当我们运行Start#main(),因为是main方法,在栈帧中的局部变量表中会先加载args,里面Customer customer = new Customer();会将customer记录到栈帧的局部变量表中,通过地址指针指向了堆中的整个实例对象。new Customer()这个实例的内部结构在堆空间记录了对象头、实例数据、填充字节。在该实例的对象头部中,记录了标记字(主要用与GC、线程安全等),通过类型指针指向方法区中对应Customer的klass类元信息。在实例数据中,会加载父类的属性以及本身属性,Customer类中引用了String对象,这是个引用类型,通过静态代码块赋值,这个字符串存在自负床变量池中。其中也引用了Account对象,这也是个引用类型,并不会将此对象属性都加载进来,只是记录了这个对象的引用地址,指向堆空间中的new Account()实例,在Account实例中,也是与Customer实例一样,包含了对象头等信息,也是通过类型指针指向方法区Account的klass类元信息。

对象的访问定位

从上文介绍对象的布局就已经能够知道对象是如何获取对象实例的。对于一个Customer customer = new Customer();我们知道其存储为三个部分,在栈帧中存储了堆区中的引用地址(reference),在堆区有个元数据指针(InstanceOopDesc)指向方法区中的InstanceKlass。总的来说,就是栈帧中记录着堆区实例化的对象地址,通过这个地址来方法对象实例。

对象访问的两种方式

对象的访问方式主要有两种方式,句柄访问和指针访问,在hotspot虚拟机中采用的是指针访问的方式。

1). 句柄访问

有些 JVM 实现可能使用了句柄访问的概念,其中对象的引用由一个句柄对象来管理,而句柄包含了对象的地址以及其他元信息。在Java堆中会开辟一个句柄池与实例池,句柄池中会通过指针指向实例对象和对象类型。
对象访问-句柄访问.png

因为采用的是句柄池指向对象实例数据,在reference中存储的是稳定的句柄地址,对象如果被移动(垃圾收集时候会移动对象)只会改变句柄的实例数据指针就行,reference本身是不用做修改。但是需要开辟一个空间来充当句柄池,这就会增加堆内存的空间占用。

2). 指针访问(Hotspot采用此方法)

在栈帧中的本地变量表中记录了堆中对象实例数据的地址,通过地址引用到堆中的对象实例数据,实例对象在通过类型指针指向方法区中的类元信息。
对象访问-指针引用.png

指针方式不用额外占用堆的空间,但是如果遇到对象移动,就需要去修改reference存储的地址。

直接内存(Direct Memory)

直接内存不是JVM运行时数据区的一个部分,也不是《Java虚拟机规范》中定义的内存区域,它是Java堆外的、直接向系统获取的内存空间。

直接内存概述

在Java虚拟机(JVM)中,“直接内存” 通常指的是使用 NIO(New I/O | Non-Blocking I/O)包中的 ByteBuffer 类,以及其中的 allocateDirect 方法所分配的直接字节缓冲区(Direct ByteBuffer)。通过DirectByteBuffer操作Native内存。

public class BufferTest {private static final int BUFFER_SIZE = 1024 * 1024 * 1024;public static void main(String[] args) {// byteBuffer 将持有一个大小为 1 GB 的直接内存缓冲区ByteBuffer byteBuffer = ByteBuffer.allocateDirect(BUFFER_SIZE);System.out.println("内存分配:" + BUFFER_SIZE + "byte");Scanner sc = new Scanner(System.in);sc.next();System.out.println("释放内存");byteBuffer = null;System.gc();}
}

以上代码,我们可以创建出一个内存为1G的直接内存,这里通过Scanner输入进行阻塞,我们可以通过进程查看所占用的内存大小。可见使用ByteBuffer#allocateDirect()会直接分配本地内存。
在这里插入图片描述

直接内存的性能

通常,直接内存的速度会比Java堆更快,读写性能高。在一些频繁使用IO的场景,可能会考虑使用直接内存。Java的NIO包是允许程序使用直接内存,用来作为数据缓冲区。
对于非直接缓冲区,读写文件需要与磁盘交互,这时就需要由用户态切换到内核态,在由内核态去对物理磁盘进行交互。这样就造成了需要进行两份内存的存储重复数据,效率低。
在这里插入图片描述

对于直接缓冲区,使用NIO就能够直接的使用操作系统给出的缓存区,只会存储一份。
在这里插入图片描述

直接内存的OOM

直接内存也有可能导致OutOfMemoryError异常。因为直接内存是存在Java堆外的,他的大小不会受限于-Xmx设置的最大堆空间,系统内存是有限的,Java堆和直接内存加起来不能超过操作系统给的最大内存。它是受限于操作系统对进程的可用虚拟内存空间。
如果是超过内存的限制,就会抛出java.lang.OutOfMemoryError: Direct buffer memory
缺点:

  • 分配回收成本比较高
  • 不受JVM的内存回收管理

直接内存大小可以通过MaxDirectMemorySize设置,如果不指定,默认是与堆的最大值-Xmx参数值一致。

总结

本此学习穿插了Java对象的内存布局,更加清楚了解到对象的创建方式以及过程,最为重要的是了解对象的布局结构,包括实例对象数据存放在堆中,类元信息在方法区,栈帧通过引用去指向对应的数据信息。对比了句柄方式和指针方式。最后学习了直接内存的内容,了解了直接内存也是会出现OOM异常。

👍创作不易,如有错误请指正,感谢观看!记得点赞哦!👍

相关文章:

【JVM系列】- 穿插·对象的实例化与直接内存

对象的实例化与直接内存 &#x1f604;生命不息&#xff0c;写作不止 &#x1f525; 继续踏上学习之路&#xff0c;学之分享笔记 &#x1f44a; 总有一天我也能像各位大佬一样 &#x1f31d;分享学习心得&#xff0c;欢迎指正&#xff0c;大家一起学习成长&#xff01; 文章目录…...

【C++干货铺】继承 | 多继承 | 虚继承

个人主页点击直达&#xff1a;小白不是程序媛 C系列专栏&#xff1a;C干货铺 代码仓库&#xff1a;Gitee 目录 继承的概念及定义 继承的概念 继承的定义 继承基类成员访问方式的变化 基类和派生类的赋值转化 继承中的作用域 派生类的默认成员函数 构造函数 拷贝构造…...

【ARM CoreLink 系列 8.1 -- SMMU 详细介绍-STE Entry 详细介绍 1】

请阅读【ARM CoreLink 文章专栏导读】 上篇文章:【ARM CoreLink 系列 8 – SMMU 详细介绍-上半部】 文章目录 ARM SMMU STE ENTRY1.1 STE ENTRYWORD[0]1.1.1 S1ContexPtr1.1.2 S1Fmt1.1.3 Config1.1.4 V(Valid)1.2 STE ENTRY WORD[1]1.2.1 S1CDMax1.2.2 S1ContextPtr1.3 STE E…...

高防CDN与WAF防火墙的协同防护:构筑网络安全堡垒

随着互联网的不断发展&#xff0c;网络安全威胁也日益增多&#xff0c;而网站作为企业在数字领域的门户&#xff0c;面临的风险更加复杂多样。在构筑网络安全堡垒的过程中&#xff0c;高防CDN&#xff08;Content Delivery Network&#xff09;与WAF&#xff08;Web Applicatio…...

golang strings包的基本操作

文章目录 golang 的字符串函数EqualFoldHasPrefixHasSuffixContainsContainsRuneContainsAnyCountIndexIndexByteIndexRuneIndexAnyIndexFuncLastIndexLastIndexAnyLastIndexFuncTitleToLowerToLowerSpecialToUpperToUpperSpecialToTitleToTitleSpecialRepeatReplaceMapTrimTri…...

高效解决在本地打开可视化服务器端的tensorboard

文章目录 问题解决方案 问题 由于连着远程服务器构建模型&#xff0c;但是想在本地可视化却做不到&#xff0c;不要想当然天真的以为CTRLC点击链接http://localhost:6006就真能在本地打开tensorboard。你电脑都没连接服务器&#xff0c;只是pycharm连上了而已 解决方案 你需要…...

Spring Boot Actuator 2.2.5 基本使用

1. pom文件 &#xff0c;添加 Actuator 依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency> 2.application.properties 文件中添加以下配置 …...

字符串相似度匹配算法_莱茵斯坦距离算法

package day0330;public class LevenshteinDistanceUtil {public static void main(String[] args) {String a "WN64 F98";String b "WN64 F98 ";System.out.println("相似度:" getSimilarityRatio(a, b));}/*** 获取两字符串的相似度* * par…...

【EI会议征稿】第九届电气、电子和计算机工程研究国际学术研讨会 (ISAEECE 2024)

第九届电气、电子和计算机工程研究国际学术研讨会 (ISAEECE 2024) 2024 9th International Symposium on Advances in Electrical, Electronics and Computer Engineering 第九届电气、电子和计算机工程研究国际学术研讨会(ISAEECE 2024&#xff09;将于2024年3月1-5日在南…...

Maven Helper插件——实现一键Maven依赖冲突问题

总结/朱季谦 业余在一个SpringBoot项目集成Swagger2时&#xff0c;启动过程一直出现以下报错信息—— An attempt was made to call a method that does not exist. The attempt was made from the following location: ​ springfox.documentation.schema.DefaultModelDepe…...

理解位运算的规则

关卡名 理解位运算的规则 我会了✔️ 内容 1.理解位运算的基本规则 ✔️ 2.理解移位的原理以及与乘除的关系 ✔️ 3.掌握位运算的常用技巧 ✔️ 在学习位操作之前&#xff0c;我们先明确数据在计算机中怎么表示的。我们明确原码、反码和补码的概念和表示方法&#xff0c;之…...

Android Bitmap 使用Vukan、RenderEffect、GLSL实现模糊

文章目录 Android Bitmap 使用Vukan、RenderEffect、GLSL实现模糊使用 RenderEffect 模糊使用 Vukan 模糊使用 GLSL 模糊RS、Vukan、RenderEffect、GLSL 效率对比 Android Bitmap 使用Vukan、RenderEffect、GLSL实现模糊 本文首发地址 https://blog.csdn.net/CSqingchen/articl…...

Vue H5页面长按保存为图片

安装依赖&#xff1a;npm install html2canvas -d <template><div class"index"><div id"captureId" class"capture" v-show"firstFlag"><ul><li>1</li><li>2</li><li>3<…...

【Web】UUCTF 2022 新生赛 个人复现

目录 ①websign ②ez_rce ③ez_upload ④ez_unser ⑤ezsql ⑥ezpop ⑦funmd5 ⑧phonecode ⑨ezrce ①websign 右键打不开&#xff0c;直接抓包发包看源码 ②ez_rce “反引号” 在PHP中会被当作SHELL命令执行 ?codeprintf(l\s /); ?codeprintf(ta\c /ffffffffffl…...

设置python下载包代理

使用场景 正常网络情况下我们安装如果比较多的python包时&#xff0c;会选择使用pip install -r requirements.txt -i https://pypi.douban.com/simple --trusted-hostpypi.douban.com这种国内的镜像来加快下载速度。 但是&#xff0c;当这台被限制上网时&#xff08;公司安全…...

nginx 配置前端项目添加https

可申请阿里云免费证书 步骤省略… nginx 配置 server {listen 8050; #默认80端口 如果需要所有访问地址都是https 需要注释listen 8443 ssl; #https 访问的端口 &#xff0c;默认443server_name 192.168.128.XX; #域名 或 ip# 增加ssl#填写证书文件…...

人群计数CSRNet的pytorch实现

本文中对CSRNet: Dilated Convolutional Neural Networks for Understanding the Highly Congested Scenes&#xff08;CVPR 2018&#xff09;中的模型进行pytorch实现 import torch;import torch.nn as nn from torchvision.models import vgg16 vggvgg16(pretrained1)import…...

【HTTP协议】简述HTTP协议的概念和特点

&#x1f38a;专栏【网络编程】 &#x1f354;喜欢的诗句&#xff1a;更喜岷山千里雪 三军过后尽开颜。 &#x1f386;音乐分享【如愿】 &#x1f970;欢迎并且感谢大家指出小吉的问题 文章目录 &#x1f33a;概念&#x1f33a;特点&#x1f384;请求协议&#x1f384;响应协议…...

经典神经网络——AlexNet模型论文详解及代码复现

一、背景 AlexNet是在2012年由Alex Krizhevsky等人提出的&#xff0c;该网络在2012年的ImageNet大赛上夺得了冠军&#xff0c;并且错误率比第二名高了很多。Alexnet共有8层结构&#xff0c;前5层为卷积层&#xff0c;后三层为全连接层。 论文地址&#xff1a;ImageNet Classif…...

flutter开发实战-轮播Swiper更改Custom_layout样式中Widget层级

flutter开发实战-轮播Swiper更改Custom_layout样式中Widget层级 在之前的开发过程中&#xff0c;需要实现卡片轮播效果&#xff0c;但是卡片轮播需要中间大、两边小一些的效果&#xff0c;这里就使用到了Swiper。具体效果如视频所示 添加链接描述 这里需要的效果是中间大、两边…...

【Flutter】graphic图表实现自定义tooltip

renderer graphic中tooltip的TooltipGuide类提供了renderer方法&#xff0c;接收三个参数Size类型&#xff0c;Offset类型&#xff0c;Map<int, Tuple>类型。可查到的文档是真的少&#xff0c;所以只能在源码中扒拉例子&#xff0c;做符合需求的修改。 官方github示例 …...

手机上的记事本怎么打开?安卓手机通用的记事本APP

有不少上班族发现&#xff0c;自己想要在电脑上随手记录一些工作文字内容&#xff0c;直接使用电脑上的记事本工具来编辑文字是比较便捷的。但是如果想要在手机上记录文字内容&#xff0c;就找不到手机上的记事本了。那么手机上的记事本怎么打开&#xff1f;安卓手机通用的记事…...

一起学docker系列之十五深入了解 Docker Network:构建容器间通信的桥梁

目录 1 前言2 什么是 Docker Network3 Docker Network 的不同模式3.1 桥接模式&#xff08;Bridge&#xff09;3.2 Host 模式3.3 无网络模式&#xff08;None&#xff09;3.4 容器模式&#xff08;Container&#xff09; 4 Docker Network 命令及用法4.1 docker network ls4.2 …...

前端OFD文件预览(vue案例cafe-ofd)

0、提示 下面只有vue的使用示例demo &#xff0c;官文档参考 cafe-ofd - npm 其他平台可以参考 ofd - npm 官方线上demo: ofd 1、安装包 npm install cafe-ofd --save 2、引入 import cafeOfd from cafe-ofd import cafe-ofd/package/index.css Vue.use(cafeOfd) 3、使…...

Java[list/set]通用遍历方法之Iterator

需求&#xff1a;输入一个字符串 将其拆解成单个汉字 然后一行一个输出 这里要求使用到Arraylist集合实现方法Itrator遍历的原理import java.util.ArrayList; import java.util.Collection; import java.util.Iterator;public class Main{public static void main(String[] arg…...

ubuntu/vscode下的c/c++开发之-CMake语法与练习

Cmake学习 1 语法特性介绍 基本语法格式&#xff1a;指令(参数 1 参数 2...) 参数使用括弧括起参数之间使用空格或分号分开 指令是大小写无关的&#xff0c;参数和变量是大小写相关的 set(HELLO hello.cpp) add_executable(hello main.cpp hello.cpp) ADD_EXECUTABLE(hello ma…...

Java(119):ExcelUtil工具类(org.apache.poi读取和写入Excel)

ExcelUtil工具类(XSSFWorkbook读取和写入Excel),入参和出参都是:List<Map<String,Object>> 一、读取Excel testdata.xlsx 1、new XSSFWorkbook对象 File file = new File(filePath); FileInputStream fis = new FileInputStream(file);…...

Kong处理web服务跨域

前言 好久没写文章了&#xff0c;大概有半年多了&#xff0c;这半年故事太多&#xff0c;本文写不下&#xff0c;就写写文章标题问题&#xff01; 问题描述 关于跨域的本质问题我这里不过多介绍&#xff0c;详细请看历史文章 跨域产生的原因以及常见的解决方案。 我这边是新…...

Kotlin学习——kt里的作用域函数scope function,let,run,with,apply,also

Kotlin 是一门现代但已成熟的编程语言&#xff0c;旨在让开发人员更幸福快乐。 它简洁、安全、可与 Java 及其他语言互操作&#xff0c;并提供了多种方式在多个平台间复用代码&#xff0c;以实现高效编程。 https://play.kotlinlang.org/byExample/01_introduction/02_Functio…...

informer辅助笔记:utils/timefeatures.py

定义了一套与时间特征相关的类和函数&#xff0c;旨在从时间序列数据中提取有用的时间特征&#xff0c;以支持各种时间序列分析和预测任务 from typing import Listimport numpy as np import pandas as pd from pandas.tseries import offsets from pandas.tseries.frequenc…...