主页

文件

2021-01-27
linux

目录介绍 #

根目录 #

目录 介绍
/bin (binary)存放很多可执行的指令,该路径下的指令可以被root和一般账号所使用,比如cat,chmod,mv,bash等
/boot 存放开机会使用到的文件,如/boot/grub
/dev linux中任何外部设备都是以文件的形态存在于这个目录中
/etc 系统主要的配置文件几乎都在这个目录中,
/lib 存放开机时会用到的库,以及在/bin或/sbin下面命令会调用的函数库。(/lib64:用来存放于/lib不同格式的支持64位的二进制函数库)
/media 存放的是可移除的设备,如光盘、dvd等,能暂时挂载到这里
/mnt 可以用来暂时挂载某些额外的设备
/opt 如果自行安装(不使用apt或yum命令安装的)可以放到这里,但一般还是习惯放到/usr/local中
/run 规定开机后所产生的各项信息要放到该文件夹中
/sbin 设置系统环境的,包括了开机、修复、还原系统所需要的指令。某些服务器软件程序一般放到/usr/sbin中,而向本机自行安装的软件所产生的系统执行文件,则放置在/usr/local/sbin中。
/srv (service)是一些网络服务启动后,这些服务所需要取用的数据目录
/tmp 暂时放置文件的位置
/home 系统默认的使用者主文件夹。如bes用户的默认文件夹就是/home/bes
/root root的主文件夹
/lost+found 使用ext文件系统格式才会产生的目录,目的是当文件系统发生错误时,将一些遗失的片段放到这
/proc 这个目录下的数据都在内存中,所以本身不占磁盘空间。如/proc/cpuinfo等。
/sys 主要记录与核心与系统硬件信息较相关的信息。不占磁盘空间
/usr (unix software resource)与软件安装有关;
/var (variable)与系统运行过程有关。

/usr #

目录 介绍
/usr/bin 一般用户能使用的指令放到这。centos7已经将全部的用户指令放到这里,使用链接的方式将/bin链接于此。
/usr/lib 与/lib功能相同,/lib就是链接到此目录中的。
/usr/local 在本机自行安装自己下载的软件,建议安装到此目录。
/usr/sbin /sbin就是链接到此目录。
/usr/share 好多文档都在这里。如/usr/share/man(在线说明文件)
/usr/include c/c++等头文件和include文件的放置位置
/usr/src 源代码建议放到这里。
/usr/libexec 某些不被一般用户惯用的执行文件或脚本等都放在此目录。例如大部分x视窗下的操作指令很多都放在此目录下。
/usr/lib64 /lib64就是链接过来的

/var #

目录 介绍
/var/cache 应用程序运行过程产生的一些暂存盘
/var/lib 程序本身执行的过程中,需要使用到的数据文件放置的目录
/var/lock 某些设备或者是文件资源一次只能被一个应用程序所使用。
/var/log 登陆文件放置的目录
/var/run 某些应用程序启动后,会将他们的pid放置到该目录,这个目录链接到了/run

/proc #

目录 介绍
目前主机上的各个进程的PID都是以目录的形态存在/proc中,如PID为1的所有相关信息都写入在/proc/1/文件夹下。
/proc/cmdline 加载 kernel 时所下达的相关指令与参数!
/proc/cpuinfo 本机的cpu相关信息,包含频率、类型。
/proc/devices 这个文件记录了系统各个主要装置的主要装置代号
/proc/filesystems 目前系统已经加载的文件系统
/proc/meminfo 使用 free 列出的内存信息,在这里也能够查阅到!
/proc/loadavg top 以及 uptime 的三个平均数值就是记录在此!
/proc/modules 目前我们的 Linux 已经加载的驱动程序
/proc/mounts 系统已经挂载的数据,就是用 mount 这个指令呼叫出来的数据啦!
/proc/swaps 到底系统挂加载的内存在哪里?使用掉的 partition 就记录在此。
/proc/partitions 使用 fdisk -l 会出现目前所有的 partition ,在这个文件当中也有纪录。
/proc/version 核心的版本,就是用 uname -a 显示的内容
/proc/bus/* 一些总线的装置,还有 USB 的装置也记录在此

Linux文件信息 #

-rw-r--r-- 1 bes bes 2625 Jan 27 11:11 _config.yml

  • 第一栏表示文件类型和权限;
    • 第一个字符代表该文件的类型,-表示文件,d表示目录,l表示链接文件(link),b表示区块文件如硬盘,在/dev/sda(block),c表示字符设备文件,如鼠标键盘(character),s表示数据接口文件(sockets),p表示数据输送档(FIFO,pipe)。
    • 下来9个字符每三个为一组(r表示可读,w表示可写,x表示可执行,-表示无该权限):
      • 第一组表示文件拥有者可具备的权限;
      • 第二组表示加入此群组的账号的权限;
      • 第三组为非本人且没有加入本群组的其他账号的权限。
  • 第二栏表示有多少文件名链接到此节点(i-node);
  • 第三栏表示该文件所属的用户,第四栏表示所属群组;
  • 第五栏表示容量大小,第六栏表示最近的修改时间,第七栏为文件名。

tips #

  • 如果用户对一个目录只有只读权限,那么是无法进入此目录的,他必须持有执行权限。
  • 对目录有只读权限表示它可以查看该目录下的文件名数据(用ls+目录名)。
  • 对目录有写权限表示它可以对该目录下的文件或目录执行:①新建文件和目录;②删除文件和目录(不论该文件的权限是什么);③修改文件或目录名;④移动文件和目录。
  • root不受权限限制。
  • 文件的写权限指可以编辑文件,但不包含删除文件。
  • umask:查看和设置文件权限。如002,表示user和group拥有全部权限,others拥有r和x权限。
  • 特殊权限(有些文件或目录会出现rws或rwt的情况,这就是特殊权限。注意:当S或者T为大写的时候,表示无效,因为使用者没有该程序的执行权限)
    • SUID(s):只对二进制文件(可执行的程序)有效;执行者要对该程序具有x的权限;在执行该程序时,执行者将短暂获得该程序拥有者(比如root)的权限。
    • SGID(s):可以针对二进制文件或目录来设置。对二进制文件:执行者要对该程序具有x的权限,在执行该程序时,执行者将获得该程序所在群组的支持。对目录:代表使用者在这个目录下面新建的文件的文件群组都会与该目录的群组名称相同。
    • SBIT(t):只针对目录有效,当使用者对该目录有w和x权限,只有自己和root才能删掉自己创建的文件或目录。
    • 权限和数字存在对应,SUID为4,SGID为2,SBIT为1。

文件系统 #

传统磁盘中,一个分区就是一个文件系统,但现在并不准确。文件系统通常将权限和属性放在inode中,将实际数据放到data block中。另外,有一个superblock记录整个文件系统的整体信息。

  • superblock:记录此文件系统的整体信息,包括inode/block的总量、使用量、剩余量,以及文件系统的格式与相关信息等;
  • inode:记录文件的属性(rwx、群组、时间参数等),一个文件占用一个inode,同时记录此文件数据所在的block号码;
  • block:实际记录文件的内容,若文件太大时,会占用多个block。 每个inode和block都有编号,inode内有文件数据的block号码。
  • 索引文件系统:上面的数据存取方法就是。
  • FAT:没有inode存在,每个block号码都记录在前一个block中,像一条链子一样。

Ext2 #

EXT2设置多个区块群组,每个区块群组都有独立的inode/block/superblock系统。 每个区块群组有6个部分:

  1. data block(数据区块):存放文件内容。Ext2中支持的block大小有1k,2k及4k,在格式化的时候就固定了,每个block只能放一个文件的数据。
1kB 2kB 4kB
最大单一文件限制 16GB 256GB 2TB
最大文件系统容量 2TB 8TB 16TB
  1. inode table(inode 表格):记录的数据:存取模式(rwx);拥有者和群组;文件的大小;文件创建时间,修改时间;读取时间;定义文件特性的flag;该文件内容的指向。
    • inode数量和大小在格式化时就固定了。
    • 每个inode大小固定为128B(新的ext4和xfs可以设置到256B);
    • 每个文件只会占用一个inode;所以文件系统能创建的文件数量与inode的数量有关;
    • 系统读取文件时需要先找到inode,在分析权限后,才进行下一步;

常量池

2021-01-27
java

常量池 #

  • 常量池中主要存放两大类常量:字面量和符号引用。
  • 字面量比较接近Java语言层面的常量概念,如文本字符串、声明为final的常量值等。
  • 符号引用包括了下面三类常量:类和接口的全限定命名、字段的名称和描述符、方法的名称和描述符。
  • 在class文件中不会保存各个方法、字段的最终内存布局信息,当虚拟机运行时,需要从常量池中获得对应的符号引用,再在类创建时或运行时解析、翻译到具体的内存地址中。

DataOutputStream的writeChars

2021-01-27
java

  • DataOutputStream的writeChars不推荐使用!
  • writeChars是将String直接拆成了byte(即先获取String对应的char数组,再将一个char分割成两个byte)。如果在客户端使用了该方法写入一个字符串,再在服务端读取,因为DataInputStream并没有readChars方法,只能使用read方法读取一个byte数组。这就会导致一个问题,byte数组转化为String会有一个编码的问题,服务端可能会出现错误。
  • 正确的姿势是使用DataOutputStream的write方法写入一个byte数组,两端使用相同的编码。

java随笔

2021-01-27
java

异常 #

  • 所有的异常都继承自Throwable;
  • Throwable有两个子类:Error,Exception。
  • Error描述了java运行时系统的内部错误和资源耗尽错误;
  • Exception有有两个分支,一个分支派生于RuntimeException,另一个分支包含其他异常。
  • 由程序错误导致的异常属于RuntimeException,例如:数组下标越界,错误的类型转换,空指针异常; 其他异常包括IOException,SQLException等。

线程 #

  • 对于sun jdk来说,它的windows版和linux版都是使用一对一的线程模型实现的,一条java线程就映射到一条轻量级进程中,因为windows和linux系统提供的线程模型就是一对一的。

cas #

  • cas指令需要有3个操作数,
  • 分别是变量的内存地址(V),旧的预期值(A)和新值(B)。
  • 当cas指令执行时,当且仅当V符合旧预期值A时,处理器用新值B更新V的值,否则他就不执行更新。 (但是无论是否更新了V的值,都会返回V的旧值。)
  • 上述的操作是一个原子操作。

class文件 #

  • 将一个局部变量加载到操作数栈Tload
  • 将一个数值从操作数栈存储到局部变量表Tstore
  • 将一个常量加载到操作数栈:bipush\sipush\ldc\Tconst_

Buffer

2021-01-27
java

Buffer #

  • 使用Buffer读写数据一般遵循四个步骤:①写入数据到Buffer;②调用flip()方法;③从Buffer中读入数据;④调用clear()或者compact()方法。
  • 缓冲区的本质是一块可以写入数据,然后可以从中读取数据的内存。
  • Buffer的三个属性:1.capacity 2.position 3.limit
    • capacity 表示该内存块的大小
    • position 当你写入数据到Buffer中,position表示当前的位置。当将Buffer从写模式切换到读模式时,position会被置为0。
    • limit 写模式下,limit等于capacity。当将Buffer从写模式切换到读模式时,limit表示你最多能读入多少数据,所以此时limit会被设置为写模式下的position值。
  • flip()方法将Buffer从写模式切换到读模式。调用该方法会将position设置为0,将limit设置为position的之前的值。
  • rewind()将position设回0。
  • clear()将position设置为0,将limit设置为capacity,表示可以写入了。
  • compact()将所有未读的数据拷贝到Buffer的起始处,然后将position设置到最后一个未读元素正后面,limit设置为capacity,表示可以写入了。
  • mark()可以记录一个特定的position。之后可以调用reset()恢复到这个位置。

java内存模型

2020-11-24
java

  • 原子性:保证指令不会受到线程上下文切换的影响
  • 可见性:保证指令不会受到cpu缓存的影响
    • synchronized和volatile都可以保证可见性
  • 有序性:保证指令不会受到cpu指令并行优化的影响

volatile #

  • 它可以用来修饰成员变量和静态成员变量,避免线程从自己的工作缓存中查找变量的值,必须到主存中获取它的值,线程操作volatile变量都是直接操作主存。

join和park

2020-11-19
java

join源码分析 #

  • join()是等待一个线程运行结束
public class Thread implements Runnable {
    //底层是使用wait()实现
    public final synchronized void join(long millis) throws InterruptedException {
        long base = System.currentTimeMillis();//开始时间
        long now = 0;//已经等待的时间

        if (millis < 0) {
            throw new IllegalArgumentException("timeout value is negative");
        }

        if (millis == 0) {//参数为0时会一直等待线程结束
            while (isAlive()) {
                wait(0);
            }
        } else {
            while (isAlive()) {
                //防止虚假唤醒,因为wait会被notify和notifyAll唤醒
                //唤醒后需要等待的时间是millis减去已经等待的时间
                long delay = millis - now;
                if (delay <= 0) {
                    break;
                }
                wait(delay);
                now = System.currentTimeMillis() - base;
            }
        }
    }
    
    public final void join() throws InterruptedException {
        join(0);
    }
}

park #

  • LockSupport.park();//暂停当前线程
  • LockSupport.unpark(暂停线程对象);//恢复某个线程的运行
  • 对应的线程状态还是wait状态
  • unpark可以在park之前执行,仍然可以恢复线程的执行

桥模式

2020-10-20
设计模式

  • 模式定义:将抽象与实现分离,使它们都可以独立地变化。
  • 应用场景:两个非常强的变化维度。

案例 #

场景

  1. 分析一下,首先会创建1个电脑类,然后创建3个电脑的子类(即电脑的类型),再创建3x3个子类。假设有n种电脑类型,m种电脑品牌,那么产生的类的数量为1+n+nxm

  2. 如果再加一个电脑品牌acer,则需要再添加三个类,即acer台式机、acer笔记本、acer平板。显然这种方式产生的类的数量非常多。

  3. 此外,这个实现违背了单一职责原则,类中出现了两个变化(电脑类型和品牌)。

  4. 解决办法:将类型写成一个抽象类,将品牌写成一个抽象类。通过一个"桥"将他们联系起来。

//品牌类
interface Brand{
    void info();
}
class Lenovo implements Brand{
    public void info(){
        //...
    }
}
class Apple implements Brand{
    public void info(){
        //...
    }
}
class Dell implements Brand{
    public void info(){
        //...
    }
}

//电脑类
abstract class Computer{
    //通过类组合来替代类继承
    protected Brand brand;
    
    public Computer(Brand brand){this.brand=brand;}
    
    abstract void info();
}

class Desktop extends Computer{
    public Desktop(Brand brand){super(brand);}
    public void info(){
        //...
    }
}

class Laptop extends Computer{
    public Laptop(Brand brand){super(brand);}
    public void info(){
        //...
    }
}
class Pad extends Computer{
    public Pad(Brand brand){super(brand);}
    public void info(){
        //...
    }
}
  1. 通过上面的修改,类的数量变成了1+n+m
  2. 在这里我理解的抽象是Brand,实现指的是Computer和Computer的子类。