关于Object 0 = new Object() 的追魂九连问

news2024/11/23 4:05:54

文章目录

  • 对象的创建过程
  • 对象的组成
  • 解析普通对象
    • **结果分析:**
      • 给对象添加属性
        • 注意事项
      • 补充
      • jvm压缩指针
        • 栗子:
  • 对象头包含什么
  • 对象怎么定位?
    • **句柄方式和直接引用的优缺点:**
  • 对象怎么分配?
  • 为什么hotspot不使用c++对象来代表java对象?
  • Class对象是在堆还是在方法区?
  • DCL要不要加volatile问题
    • DCL
    • 指令重排
    • volatile

来源于:B站马士兵的jvm视频总结!!

1、解释一下对象的创建过程?(半初始化)

2、DCL要不要加volatile问题?(指令重排)

3、对象在内存中的存储布局?(对象与数组的存储不同)

4、对象头具体包含什么?

5、对象怎么定位?(直接、间接)

6、对象怎么分配?(栈上-线程本地-Eden-Old)

7、Object 0 = new Object()在内存中占多少个字节

8、为什么hotspot不使用c++对象来代表java对象?

9、Class对象是在堆还是在方法区?

对象的创建过程

当执行 Object o = new Object(); 这行代码时,一个新的 Object 对象会被实例化,而这个对象实例会存储在堆内存中。Object o 实际上是一个引用变量,它存储在栈内存中,指向堆内存中的那个 Object 对象。通过这种方式,我们可以通过引用变量 o 来访问和操作堆中的 Object 对象。当 o 超出其作用域或被重新赋值时,堆中的 Object 对象仍然存在,直到垃圾收集器回收不再使用的对象。

  1. new Object():这是一个对象的实例化过程。new 关键字用于在内存中分配空间来存储新的对象。Object() 是一个构造函数调用,用于初始化 Object 类的新实例。
  2. 对象的内存分配:new Object() 表示在Java堆中分配了一块内存空间,用于存储一个新的 Object 对象。
  3. 构造函数的执行:一旦分配了内存空间,就会调用 Object 类的构造函数。在这种情况下,Object 类是Java中所有类的基类,它的构造函数是一个无参构造函数,因此没有任何参数传递。
  4. 初始化对象:在构造函数执行完毕后,对象被初始化为 Object 类的实例。此时,Object o 引用变量被赋值为指向这个新创建的对象。

注意事项:

在实际开发中,我们通常不会直接使用 Object 类的实例,而是创建自定义类,然后实例化自定义类的对象来进行具体的业务操作。Object o = new Object(); 这种形式通常在示例代码或一些基础概念演示中使用。

当刚new出来一个对象时,所有成员变量都有一个默认值,只有当调用构造方法时才会赋值;例子:

public class test {
    int n = 8;
}
  1. 申请空间,给默认值0,而不是8,
  2. 调用构造方法赋值
  3. 引用,建立关联

对象的组成

img

1、markword:

8字节

2、class pointer(类型指针)

4字节

意思是当你new的是什么对象时,它指向的就是什么.class,规定一个对象具体是什么对象

例如:

new User(),那它指向的就是User.class

3、instance data(实例数据)

放入一个对象的成员变量,比如:

当User()对象里有一个属性是String name;时,那么这个name这个属性就是放在这里面

4、padding(对齐)

就是为了让数据对齐,假如前面那3个部分加起来不能被8字节整除,则自动补充尾数,直到能被8整除

为什么是8字节呢?因为8字节是64个bit,我们虚拟机或者说电脑来说就是64位,所以一次性存储64位对它来说是最方便的

比如我装货卸货的时候必须是一次64个,那当我的货只有63个时,我将补充一个空的货

解析普通对象

1、我们采用JOL(Java Object Layout)类库来解析对象,依赖:

<!-- https://mvnrepository.com/artifact/org.openjdk.jol/jol-core -->
<dependency>
    <groupId>org.openjdk.jol</groupId>
    <artifactId>jol-core</artifactId>
    <version>0.9</version>
</dependency>

2、使用:

package com.example.demo.web;

import org.openjdk.jol.info.ClassLayout;

/**
 * com.example.demo.web
 *
 * @version Id: test, v 0.1 2023/7/14 14:19  Exp $
 */
public class test {
    private static class T{

    }
    public static void main(String[] args) {
        T t = new T();
        System.out.println(ClassLayout.parseInstance(t).toPrintable());
    }
}

3、运行结果:

image-20230726155157224

结果分析:

可以看到第一行和第二行都是4个字节,而且代表的是对象头,前面我们说markword是由8个字节组成,那么第一行和第二行加起来就是代表markword

第三行代表的是class pointer(类型指针),所以可以通过value的4个字节找到T.class

第四行显示loss due to the next object alignment代表的是补齐4个字节,让8整除

image-20230726155426459

所以可以得出Object 0 = new Object()一共占用16个字节,也就解决了第7个问题

给对象添加属性

我们给对象添加一个int a,那么这个对象占多少个字节呢?

private static class T{
	int a;
    }

其实很好计算,int类型在java中就占4个字节,所以我们的执行结果是:

image-20230726164100739

这里的第4行就不是补齐了,是instance data(实例数据)

因为加起来正好16个字节,可以被8整除,所以没有补齐这一部分

Java中8大数据类型对应的字节大小:

类型字节位数
byte
short16
int32
long64
float432
double864
char216
boolean1(通常是1个)8
String464

注意事项

  1. boolean类型虽然只占1个字节,但因为在jvm中会把它转换为int类型,所以它会补齐3个,所以也是占4个字节,byteshort同理;这重情况叫做内部对齐
  2. String字段填写值,比如在T对象中添加属性String s = "hello",它也是占4个字节,因为hello是存在字符串常量池中的,和对象本身是没关系的,只是可以通过这4个字节在常量池中找到对应字符

补充

jvm的指针长度是多少,由什么来决定呢?

长度的意思也就是说电脑的寻址能力有多强,能有多少中bit组合。每种组合就代表一个地址

由电脑的位数来决定:

image-20230726170320686

随着电脑的运行内存的增大,就必须由高位的操作系统才能支持,比如32位的电脑,最大支持的运行内存就是2的32次方,也就是4G

那为什么String的指针只有4个字节呢?也就是32位呢?

因为使用了压缩指针,因为大多数的机器,用32位已经绰绰有余,就是为了省空间

jvm压缩指针

我们可以看到java启动参数有一个-XX:+UseCompressedClassPointers意思是启用压缩类指针,一般我们启动jar包时都会携带这个参数;(默认)

如果没有,普通类不是由4个部分组成吗!那么它其中的class pointer类型指针,就是8个字节了,而不是4个字节

以及-XX:+UseCompressedOops,oops指的是:ordinary object pointers (普通对象指针)一样进行了压缩,也就是String这样的对象

栗子:

1、把压缩指针关掉:

image-20230726173238081

把+改成-即可

2、运行结果:
image-20230726173400519

可以看到第1、2、3、4行全是Object header,第1、2代表的是markword,第3、4行就代表的是类型指针了,多了4字节!

对象头包含什么

由上面我们可以得知:对象头包含一个markwordclass pointer类型指针

class pointer在上面已经说过,就是地址,比较简单,所以一般这样问的话就是问markword中有什么?

image-20230727155924514

回收时需使用三色标记,当前 处于什么颜色就存在markword中的GC标记信息中,以及分代年龄

我们可以看到markword中还存着hashCode,当你调用hashCode时才会存储,不然为null,这样设计的目的就是,调用一次hashCode之后,这个hashCode是不变的,下次再调用就是直接拿markword中的值了,不需要重新计算;

1.hashcode调用前后对比:

image-20230727160931411

2.锁前后对比:

image-20230727161508889

发现上完锁之后,markword信息发生了变化,所以锁信息是存放在markword中的

到这里第3、4、7个问题得到了解决!!!!

对象怎么定位?

两种方式:

image-20230727163253123

句柄方式(Handle-Based Approach)是一种内存管理方式,用于处理对象在内存中的定位和访问。在句柄方式中,对象的引用由两部分组成:句柄和实际对象。

具体来说,句柄方式中有两级间接寻址:

  1. 句柄(Handle):每个对象的引用变量并不直接指向对象本身,而是指向一个句柄对象。句柄对象是一个固定大小的数据结构,其中包含了实际对象的地址(或者称为指针)和其他元数据信息。实际引用变量中存储的是指向句柄对象的引用。
  2. 实际对象:句柄对象中包含了指向实际对象的地址。通过这个地址,可以访问到实际的对象数据。

通过引入句柄对象,Java虚拟机可以更好地管理内存。由于句柄对象是固定大小的,它们可以在堆中更容易地进行移动和重新分配。而实际对象的地址则可以在句柄中进行更新,而无需修改引用变量的值。

Java曾经采用句柄方式作为一种内存管理方式,但从JDK 1.4版本开始,大部分的Java虚拟机实现转向使用直接引用的方式,即直接将引用变量指向实际对象,避免了句柄对象的额外开销,提高了访问效率。目前,大多数Java虚拟机都不再使用句柄方式。句柄方式在Java之外的其他编程语言和部分特定的嵌入式系统中可能仍然有应用。

句柄方式和直接引用的优缺点:

因为GC的回收涉及到对象的移动,所以对应的需要修改指针地址

存管理方式,在不同的情况下各有优缺点。下面是它们各自的优缺点:

句柄方式的优点:

  1. 内存管理灵活:句柄对象的固定大小使得内存管理更加灵活。因为句柄对象可以在堆中更容易地移动和重新分配,从而减少了碎片化问题,有利于提高内存的利用率。
  2. 安全性:句柄对象可以提供更好的安全性。由于引用变量存储的是指向句柄对象的引用,而不是指向实际对象的地址,可以在运行时做更多的安全检查和控制,防止悬空指针和野指针等问题。

句柄方式的缺点:

  1. 性能损失:由于句柄对象和实际对象之间需要进行两级间接寻址,这增加了访问对象数据的开销,导致性能上的损失。尤其是在频繁访问对象时,句柄方式可能会导致额外的开销。
  2. 需要额外内存:句柄方式需要为每个对象都分配额外的句柄对象,这会导致额外的内存开销。这在对象数量较多时可能会成为问题。

直接引用的优点:

  1. 性能更高:直接引用避免了句柄方式中的两级间接寻址,直接将引用变量指向实际对象,因此访问对象数据更加高效,减少了额外开销,提高了性能。
  2. 内存开销较小:直接引用不需要额外的句柄对象,节省了内存开销。这对于对象数量较大或内存有限的场景非常有利。

直接引用的缺点:

  1. 内存管理相对困难:直接引用使得内存管理相对困难,因为实际对象在堆中的位置可能会发生变化,导致引用的失效。为了解决这个问题,需要引入更复杂的内存管理策略,如压缩算法等。

综合来看,直接引用方式在性能和内存开销上更优,因此成为目前主流的内存管理方式。但是句柄方式在一些特定的场景下可能仍然有一定的优势,尤其是在安全性和内存管理灵活性方面。不同的编程语言和系统根据具体需求可能会选择适合的内存管理方式。在Java中,目前的主流Java虚拟机都采用了直接引用的方式。

对象怎么分配?

image-20230727173655824

  1. 当我们new一个对象时,先会尝试是否能在栈上分配,如果可以,就直接存在栈上,不行才会在堆空间(通过逃逸分析来判断是否能在栈上分配)

    **逃逸分析:**指的是一个对象是否被传递到了方法外部,即对象的引用是否在方法的生命周期之外继续存在。如果对象没有逃逸,它的生命周期仅限于方法的执行过程,那么编译器可以选择将该对象在栈上分配内存而不是在堆上分配。这样做的好处是,在栈上分配的对象可以随着方法的退出而自动销毁,无需垃圾收集器的介入,减少了内存的使用和垃圾收集的开销,从而提高了程序的性能。

  2. 判断对象是否大,如果过大则直接分配到老年代,(通过JVM参数控制)

  3. 经过TLAB分配,进入到新生代(E区-诞生区)

    TLAB:代表线程本地分配缓冲区(Thread-Local Allocation Buffer),是Java虚拟机(JVM)中的一种内存分配优化技术。

    在Java中,对象的创建通常是在堆内存中进行的。为了提高对象的分配效率,JVM引入了TLAB机制。TLAB是每个线程私有的一块内存区域,用于在线程本地进行对象的分配。每个线程都有自己的TLAB,从而避免了多线程竞争分配内存的问题。

    需要注意的是,TLAB机制只在启用了线程本地分配缓冲区的情况下才会生效。可以通过JVM参数来控制TLAB的启用和大小,例如使用-XX:+UseTLAB来启用TLAB,使用-XX:TLABSize来设置TLAB的大小。在大多数情况下,JVM会根据硬件和应用程序的特点自动调整TLAB的大小。

  4. 在E区经过GC之后,回收掉了就结束,没回收掉就会进入S区(也就是幸存者区域)

  5. 如果再次GC还没清除掉,则判断年龄大小,达到赋值则进入老年代,没有则进入S2,(第二个幸存者区域),如此反复,直到GC回收掉

为什么hotspot不使用c++对象来代表java对象?

hotspot指的是Java虚拟机(Java Virtual Machine,JVM)的一种实现,HotSpot虚拟机以高性能为目标,通过即时编译(Just-In-Time Compilation,JIT)技术来将Java字节码转换为本地机器码,从而提高Java应用程序的执行速度。

  1. C++对象有一个virtual table 这个是java对象所没有的。所以相对应的c++的对象会占用内存更多
  2. 对象头信息:Java对象在HotSpot中包含对象头信息,用于存储元数据,如哈希码、锁状态、GC信息等。这些信息在C++对象中无法直接表示。
  3. 垃圾回收:Java虚拟机需要进行垃圾回收来管理内存,回收不再使用的对象。而C++没有垃圾回收机制,需要手动管理内存。(HotSpot中存有GC信息)
  4. 跨平台性:Java是一种跨平台的编程语言,而C++的对象模型和内存布局在不同平台上可能会有差异。使用C++对象来表示Java对象可能会导致不同平台之间的兼容性问题。
  5. JNI交互:Java虚拟机支持与本地代码的交互,通过JNI(Java Native Interface)可以调用C++代码。为了与Java对象交互,Java虚拟机需要一种独立于C++对象的对象表示方式。

Class对象是在堆还是在方法区?

在堆中

存放在方法区当中的是类的元数据,即类加载器从class文件中提取出来的类型信息、方法信息、字段信息等。元数据中又保存着指向class对象的引用。

参考文章

DCL要不要加volatile问题

需要!

cpu不一定是按照顺序执行程序,可能会出现乱序

DCL

DCL(双重检查锁定),经典例子是单例模式,双重检查锁定利用了以下两个原则:

  1. 减少同步开销: 通过首先检查实例是否已经创建,如果没有创建,再进行同步操作,从而减少了不必要的同步开销。
  2. 保证线程安全: 在同步块内进行实例的创建操作,确保只有一个线程能够成功创建实例。
public class Singleton {
    private volatile static Singleton instance; // 使用volatile确保可见性

    private Singleton() {
        // 私有构造方法
    }

    public static Singleton getInstance() {
        if (instance == null) { // 第一次检查,避免不必要的同步
            synchronized (Singleton.class) {
                if (instance == null) { // 第二次检查,确保只有一个线程创建实例
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }
}

指令重排

在第一个问题我们说了Object 0 = new Object()大体分为三步:

  1. new 申请空间,半初始化对象,也就是给默认值
  2. 调用构造方法,赋值
  3. 引用,建立关联

这是按照正常顺序执行,但CPU会出现乱序执行,就一定会出现这三步乱序的问题,比如132的顺序,假如这种情况发生(还是拿上面单例模式举例),就会出现还没完成初始化,只是半初始化就会得到一个对象

image-20230810173606371

volatile

volatile 是一个关键字,用于修饰变量,它的作用是确保变量在多线程环境下的可见性和禁止指令重排。volatile 变量具有以下作用:

  1. **可见性(Visibility):**当一个变量被声明为 volatile 时,任何线程对该变量的修改都会立即对其他线程可见,即使是在不同的CPU核心上。这可以确保当一个线程修改了 volatile 变量的值后,其他线程能够立即看到最新的值,避免了线程之间的数据不一致问题。
  2. **禁止指令重排:**在多线程环境下,编译器和处理器为了提高执行效率可能会对指令进行重排,这种重排可能会影响多线程程序的正确性。通过将变量声明为 volatile,可以防止编译器和处理器对该变量相关的指令重排,从而确保操作的顺序符合程序员的预期。

volatile

volatile 是一个关键字,用于修饰变量,它的作用是确保变量在多线程环境下的可见性和禁止指令重排。volatile 变量具有以下作用:

  1. **可见性(Visibility):**当一个变量被声明为 volatile 时,任何线程对该变量的修改都会立即对其他线程可见,即使是在不同的CPU核心上。这可以确保当一个线程修改了 volatile 变量的值后,其他线程能够立即看到最新的值,避免了线程之间的数据不一致问题。
  2. **禁止指令重排:**在多线程环境下,编译器和处理器为了提高执行效率可能会对指令进行重排,这种重排可能会影响多线程程序的正确性。通过将变量声明为 volatile,可以防止编译器和处理器对该变量相关的指令重排,从而确保操作的顺序符合程序员的预期。

需要注意的是,尽管 volatile 能够解决一些多线程问题,但它并不能完全取代锁。volatile 只适用于某些特定的场景,如标识状态变量、控制开关等,它无法保证复合操作的原子性,也无法解决一些更复杂的线程同步问题。对于一些需要保证原子性和临界区操作的情况,还是需要使用锁或其他线程同步机制

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

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

相关文章

【JavaScript】一文详解事件循环机制

目录 一、是什么 二、同步任务和异步任务 三、宏任务和微任务 小结&#xff1a;微任务是跟屁虫&#xff0c;一直跟着当前宏任务后面代码执行到一个微任务就跟上&#xff0c;一个接着一个。 例子理解&#xff1a; 五、题目巩固 六、总结 一、是什么 首先JavaScript是一种…

CAD练习——绘制电路

绘制如图交叉的六条线&#xff1a; 修剪&#xff0c;在右侧绘制如图的线&#xff1a;&#xff08;平移O&#xff09; 修剪 效果&#xff1a; 绘制电路触点 B:块编辑器&#xff0c;设置为块 添加触点到其他几个位置&#xff08;I&#xff1a;插入&#xff09; 绘制其他电路器件…

【Linux】内核宏定义解释postcore_initcall,arch_initcall,subsys_initcall

postcore_initcall postcore_initcall(pcibus_class_init) 是一个宏&#xff0c;用于在Linux内核初始化过程中注册一个后期初始化函数。 这个宏的含义如下&#xff1a; postcore_initcall 是一个宏定义&#xff0c;用于指定注册的函数在内核初始化的哪个阶段执行。 pcibus_cl…

GOLANG进阶 之 接口(interface) 与 管道(channel)

好久没有跟新过文章了&#xff0c;小编最近有点忙&#xff0c;写文章的频率下降了许多&#xff0c;但是还是会持续跟新的&#xff0c;希望关注的同学仔细学习。 首先讲一下接口具体是个啥&#xff1f;小白可以结合官方定义和小编自己的理解共同学习下 官方解释&#xff1a;接口…

MATLAB程序初始化OpenFOAM颗粒位置

问题引入 在OpenFOAM的颗粒两相流求解器中&#xff0c;我们可以采用manualInjection的方式进行自定义颗粒的初始位置&#xff0c;这个命令十分方便&#xff0c;在CFDEM中也有类似的命令&#xff0c;不过CFDEM中的命令更加强大&#xff0c;我们不仅可以定义颗粒的初始位置&…

Dockerfile 简单实战

将flask项目打包成镜像 1. 准备flask文件 创建 app.py 文件&#xff0c;内容如下 from flask import Flask app Flask(__name__)app.route(/) def hello_world():return Hello Worldif __name__ __main__:app.run(host0.0.0.0, port8000, debugTrue) 并开启外网访问&#xf…

C# 使用FFmpeg.Autogen对byte[]进行编解码

C# 使用FFmpeg.Autogen对byte[]进行编解码&#xff0c;参考&#xff1a;https://github.com/vanjoge/CSharpVideoDemo 入口调用类&#xff1a; using System; using System.IO; using System.Drawing; using System.Runtime.InteropServices; using FFmpeg.AutoGen;namespace F…

云原生是什么

目录 1. 云原生是什么1.1. 微服务1.2. DevOps1.3. 持续交付1.4. 容器化 2. 什么是云原生2.1. 云原生的诞生2.2. 云原生基金会2.3. 主要区别: 云原生与传统企业应用 1. 云原生是什么 云原生是面向"云"而设计的应用, 因此技术部分依赖于传统云计算的 3 层概念, 基础设…

二叉树题目:根据二叉树创建字符串

文章目录 题目标题和出处难度题目描述要求示例数据范围 解法一思路和算法代码复杂度分析 解法二思路和算法代码复杂度分析 题目 标题和出处 标题&#xff1a;根据二叉树创建字符串 出处&#xff1a;606. 根据二叉树创建字符串 难度 3 级 题目描述 要求 给你二叉树的根结…

Git 代码分支规范

目的 俗话说&#xff1a;没有规矩&#xff0c;不成方圆。遵循一个好的规章制度能让你的工作事半功倍。同时也可以展现出你做事的认真的态度以及你的专业性&#xff0c;不会显得杂乱无章&#xff0c;管理困难。Git分支规范也是一样。当遵循了某种约定的Git分支&#xff0c;在代…

欧拉公式的证明-泰勒展开法

欧拉公式 欧拉公式在理工科有着广泛的应用和影响。 特别地&#xff0c;当时&#xff0c;&#xff0c;巧妙地将自然对数底数 &#xff0c;圆周率 &#xff0c;虚数单位 &#xff0c; 写进一个公式。 证明 由泰勒公式&#xff1a; 即 提取奇偶次项&#xff1a; 即 补充&#xf…

Michael.W基于Foundry精读Openzeppelin第23期——ERC165Checker.sol

Michael.W基于Foundry精读Openzeppelin第23期——ERC165Checker.sol 0. 版本0.1 ERC165Checker.sol 1. 目标合约2. 代码精读2.1 supportsERC165InterfaceUnchecked(address account, bytes4 interfaceId)2.2 supportsERC165(address account)2.3 supportsInterface(address acc…

Docker一键部署项目,无需登录XShell

文章目录 一键部署项目Docker手动部署SpringBoot项目编写docker部署的脚本文件script.sh 脚本内容 特别注意&#xff01;编写dockerfiledockerfile 文件内容 上传后端服务的jar包到服务器中执行 script 脚本部署后端服务 自动部署SpringBoot项目引入jsch依赖编写jsch工具类执行…

C# byte[]与Bitmap互转

首先先观察一下本地bmp图像结构(参考&#xff1a; https://blog.csdn.net/qq_37872392/article/details/124710600)&#xff1a; 可以看到bmp图像结构除了纯图像像素点位信息&#xff0c;还有一块未用空间(OffSet)。 所以如果需要得到图像所有数据进行转换&#xff0c;则可以使…

MySQL_SQL性能分析

SQL执行频次 语法&#xff1a; SHOW GLOBAL STATUS LIKE COM_类型; COM_insert; 插入次数 com_delete; 删除次数 com_update; 更新次数 com_select; 查询次数 com_______; 注意&#xff1a;通过语法&#xff0c;可以查询到数据库的实际状态&#xff0c;就可以知道数据库是以增删…

macos搭建appium-iOS自动化测试环境

目录 准备工作 安装必需的软件 安装appium 安装XCode 下载WDA工程 配置WDA工程 搭建appiumwda自动化环境 第一步&#xff1a;启动通过xcodebuild命令启动wda服务 分享一下如何在mac电脑上搭建一个完整的appium自动化测试环境 准备工作 前期需要准备的设备和账号&…

【独立版】新零售社区团购电商系统生鲜水果商城兴盛优选十荟团源码

【独立版】新零售社区团购电商系统生鲜水果商城兴盛优选十荟团源码

DNSlog注入(利用DNSlog平台将SQL盲注变成回显注入)

前言什么是UNC什么是DNSlog注入DNSlog注入的条件防止DNSlog注入的几个措施 sqli-labs试验 前言 前几天面试的时候&#xff0c;面试官问我知不知道OOB&#xff08;带外数据&#xff09;。 当时我蒙了&#xff0c;确实没听说过这个东西&#xff0c;然后面试官告诉我原来dnslog注入…

机器人CPP编程基础-04输入Input

机器人CPP编程基础-03变量类型Variables Types ……AI…… C #include<iostream> // 引入iostream库&#xff0c;这个库包含了对输入/输出进行操作所需的函数和对象 using namespace std; // 使用命名空间std&#xff0c;这样我们就可以直接使用std中的名字&#xff0c…

设定嵌入式linux系统的用户名和密码

遇到一个问题&#xff0c;板子上电后&#xff0c;串口可以正常输入命令行&#xff0c;而且不需要密码&#xff0c;用户名就是root &#xff0c;因为没有设置密码&#xff0c;但是SSH登录时用户名输入root&#xff0c;密码直接敲回车键也就是不输入密码竟然是错误的&#xff0c;…