文件流操作引发一系列相关问题---cpu底层-----java虚拟机

时间:2021-06-14 23:30:53
public class Main  {
   
    public static void main(String arg[]){
    File file=new File("E:/TEST.TXT");
    if (!file.exists()) {
    try {
    file.createNewFile();
    } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
}
    }

              //常用字节、字符流操作
try {
    OutputStream out=new FileOutputStream(file);
InputStream in=new FileInputStream(file);
//DataOutputStream(InputStream in)
//BufferedInputStream(inputStream in)缓存
//FileReader(file/String filename)  
//InputStreamReader(InputStread
//BufferedReader(reader in)
//RandomAccessFile(File/String,String mode)
//Serializable
//ObjectInputStream(inputStream in)
//注意:对象序列化只能保存对象的非静态成员变量的值,不能保存任何的成员函数和静态的成员变量的值
//对于某些瞬时状态对象也不能保存 如thread或者一个FlieInputStream对象,对于某些字段(不永久存储的,安全),必须使用
//transient标识,否则编译不通过 
byte arr[]=new byte[1024];

Scanner sc=new Scanner(System.in);
  arr=sc.next().getBytes();
   
System.out.print(arr[1]);

   out.write(arr);
   
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
   
    }  
    /* 16位cpu
     * cpu内部:运算器、控制器、存储器
     * cpu与外部器件交流是通过外部总线的
     * 地址总线:寻址能力有关 640K 20根地址线  
     * 数据总线:cpu一个时间周期内能处理多少位的数据(寄存器有关16位)
     * 控制总线:控制总线有多少根与计算机有多少个扩展槽接口有关
     * cpu内部器件交流是内部总线
     * 运算器:加、减、乘、除
     * 段寄存器:通用寄存器16位(ax、bx、cx、dx)、代码寄存器(cs、Ip)、
     * 堆栈段寄存器(sp、ss)、数据段寄存器(ds)、
     * ax(ah,al)\x2321  ah=\x23 al=\021
     * 为什么分为ah与al呢?
     * 这是因为他们的寄存器位数为16位。而地址线是20根,导致有些地址访问不到
     * 物理地址=基地址(段地址左移一位)+偏移地址
     * 12300=10000(1000左移一位为10000)+2300
     * 执行控制:执行指令
     * 把所有外部器件所拥有的ram(随机存储、读写速度快、断电就失去记忆)或者rom(只能读不能写 )
     * 看成是一个完整的内存(物理内存),存储最小单位是一个字节 也就是8位,cpu与外部器件交流就是读写这块内存
     * 当存储一个字时,存储方式有大端小端模式,大部分cpu采用小端模式,(flash、硬盘、光盘也采用小端模式,适合计算机处理逻辑)即低位存低地址(先存低位)
     * 大端模式 即高位存地址(先存高位)符合人类逻辑。
     * A3O1 ------------>1010 0011 0000 0001(16进制对应二进制)
     * 不管是大端小端:A3是高位占8位 一个字节 01是低位
     * 在内存存储方式
     *  低端模式  低 *01*      高端模式  低*A3*
     *                         *A3*                           *01*
     *                         * *
     *                    高 * *                            高
     *  
     *  问题:
     *  单任务:一次只能运行一个程序
     *  内存小:运行一个程序,需把程序全部加载到内存
     *  不安全:直接访问物理内存,如果对bios等修改容易发生致命错误
     */
    /* 32位cpu
     * 分为实模式和保护模式
     * 保存了cs/ds/es/ss寄存器为了兼容16位 但它们存的不再是段地址,而是描述是否为
     * 局部描述符表LDTR或者全局描述符表GDTR,还通过选择子从多个局部LDT或者全局描述符GDT选择一个描述符
     * 而LDTR和GDTR两个寄存器存的是当前正在使用LDT和GDT首地址
     * 访问物理内存过程:
     * 根据访问的段,选择段寄存器
     * 根据选择子描述符地址*8+描述符表标识位中的位置(从LDTR或者GDTR中找到LDT或者GDT首地址),得到段描述符地址
     * 再从段描述符地址中Base中获得段首地址
     * 物理地址 =逻辑地址中偏移地址+段首地址
     * 
     * 分页:
     * 如果段寄存器16位中那个位标识采用分页的形式访问内存,那么线性地址就是物理地址
     * 如果使用分页访问那线性地址就是逻辑地址,根据
     * 内存=虚拟内存(指定硬盘中的一个交换文件)+物理内存
     * 虚拟内存:不把程序全加载到内存,把一部分放到虚拟内存
     * 线性地址:不采用分页访问内存,线性地址就是物理地址
     * 虚拟空间(交换分区):虚拟内存,
     * 虚拟内存(注意两个概念的虚拟内存):每一个可执行文件(包含数据和代码指令)被加载器映射很多页 每页4K  当虚拟内存(逻辑的)大于
     * 物理地址时,出现缺页就发生页面交换,虚拟内存映射到虚拟内存(交换分区)充当物理内存
     * 一级页表
     * 逻辑地址(线性地址)=页号+页内地址
     * 页寄存器:存储页的起始地址与页表长度
     * 页号与页的起始地址相加得到页表在物理内存的起始地址,
     * 页表中映射规则可以得到物理页号
     * 根据物理页号和页内偏移得到实际物理地址
     * 
     * 但每次都都要访问两次物理内存,浪费资源和时间
     * 高级缓存方法:在MMU中加一个缓存区tlb(寄存器)
     * 就是把页表中的映射信息缓存起来,当访问某一个物理地址时先访问,在TLB寄存器中的页表中是否有对应的物理地址。有就
     * 不必去内存中找页表.
     * 多级页表可以扩展物理地址 满足64位系统要求
     * 
     * 由于单核处理器运行速度已经达到一个瓶颈:
     * 采用多核(横向扩展)处理器
     * 单核时代:分为单任务和多任务
     * dos是单任务的、每个任务必须来
     * 多任务:把每一个任务分为几份,让不同任务轮流来执行,由于cpu运行速度快,所以感觉是同时执行多任务的
     * 多核处理器:单核处理器一个cpu处理多个作业,发生错误就死机了,而且任务多执行就满了,采用多核技术后
     * 可以同时处理多个作业,响应快,不容易死机,但消耗大。
     */
    /** java虚拟机
     * java实现跨平台,就是使用类似代理 中间件功能----java虚拟机----把字节码文件解释成原始机器指令
     * 我们都知道机器指令是cpu能识别执行的
     * c程序经过编译连接后变成二进制机器指令------
     * java经过编译后变成二进制jvm识别的指令
     * 虚拟机功能是:jvm识别指令变成机器指令
     * 首先虚拟机在操作系统中就是一个程序,它运行时,系统会分一块 内存给它。
     * 这一块内存叫 运行数据区域。它分为以下几个部分:
     * 计数器:记录当前线程所执行字节码的行号 每条线程都有独立的计数器
     * jvm栈   线程私有,随线程创建而创建,里面有有基本类型变量,返回结果、非基本类型对象仅存放一个指向堆的地址
     * 堆 存放对象内存  用GC管理内存   可用-xms和-xmx设定大小,创建对象使用内存超过它大小,会发超内存错误
     * 方法区域:存放类、字段、方法、静态变量、final类型常量信息,可用-xx:permsize和-xx:maxpersize调整大小,一样超它规定最大内存会出错
     * 运行时常量池:存放类中固定的常量信息、字段、方法的引用信息,类或接口类在该类的class文件被java虚拟机成功装载时分配。
     * 本地方法堆栈
     * 
     * 类加载过程:
     * 加载-----》验证----》准备-----》解析-----》初始化
     * 加载:把class字节码文件从文件系统加载到运行数据区域(操作系统划分给虚拟机的那块内存)
     * 验证、准备、解析这三个阶段叫连接
     * 验证:验证字节码是否符合java规范和虚拟机规范
     * 准备:为这个类的成员变量分配内存并设置它的初始值为0 null 就是java默认初始值  比如int 是0 boolean是false
     * 解析:符号引用---》直接引用 即符号 ---》地址  字符--->地址数值
     * 初始化:先执行无参构造函数搜索所有的类变量赋值和static{}代码块(类变量赋值和静态代码块是在编译器编译时收集合成在无参构造函数中),这个无参构成函数防止多个线程同时操作,采用加锁或者同步方法。
     * 如果一个类或者接口没有类变量赋值或者static{}代码块,可以不生成构造函数
     * 接口不能使用静态语句块,但可以赋值,所以生成无参构造函数,但不要求先执行父类的构造函数
     * 
     * 类加载器组成
     * Bootstrap class loader:
     * 当运行java虚拟机时,这个类加载器被创建,它加载一些基本的java API,包括Object这个类。
     * 需要注意的是,这个类加载器不是用java语言写的,而是用C/C++写的。
     * Extension class loader:
     * 这个加载器加载出了基本API之外的一些拓展类
     * -System Class Loader:
     * 它加载应用程序中的类,也就是在你的classpath中配置的类。
     * User-Defined Class Loader:
     * 这是开发人员通过拓展ClassLoader类定义的自定义加载器,加载程序员定义的一些类。
     * 
     * 
     * 当用户自定义加载器加载一个类时,先从System 命名空间判断是否有该类了,没有就委派给上一层
     * Extension,没有就给Bootstrap,也没有,就往下开始加载,直到有结果。
     * 注意:特定的类加载器只能加载一个类,但一个类可以被多个类加载器加载
     * 
     */
    //java调用外部程序
    /*每个运行的应用程序都有一个Runtime类,它不能创建实例,只能由getRuntime()方法获得
     * 1 它可以调用系统程序,或者执行系统dos命令
     * 2 它还可以调用gc(),运行无用单元自动收集器,调用freeMemory(),totalMemory()查看堆内存使用情况
     * 
     */
}