《揭秘Java虚拟机:JVM设计原理与实现》从源码角度解读HotSpot的内部实现机制,本书主要包含三大部分——JVM数据结构设计与实现、执行引擎机制及内存分配模型。 数据结构部分包括Java字节码文件格式、常量池解析、字段解析、方法解析。每一部分都给出详细的源码实现分析,例如字段解析一章,从源码层面详细分析了Java字段重排、字段继承等关键机制。再如方法解析一章,给出了Java多态特性在源码层面的实现方式。《揭秘Java虚拟机:JVM设计原理与实现》通过直接对源代码的分析,从根本上梳理和澄清Java领域中的关键概念和机制。 执行引擎部分包括Java方法调用机制、栈帧创建机制、指令集架构与解释器实现机制。这一话题是《揭秘Java虚拟机:JVM设计原理与实现》技术含量高的部分,需要读者具备一定的汇编基础。不过千万不要被“汇编”这个词给吓着,其实在作者看来,汇编相比于高级语言而言,语法非常简单,语义也十分清晰。执行引擎部分重点描述Java源代码如何转换为字节码,又如何从字节码转换为机器指令从而能够被物理CPU所执行的技术实现。同时详细分析了Java函数堆栈的创建全过程,在源码分析的过程中,带领读者从本质上理解到底什么是Java函数堆栈和栈帧,以及栈帧内部的详细结构。 内存分配部分主要包括类型创建与加载、对象实例创建与内存分配,例如new关键字的工作机制,import关键字的作用,再如java.lang.ClassLoader.loadClass()接口的本地实现机制。 《揭秘Java虚拟机:JVM设计原理与实现》并不是简单地分析源码实现,而是在描述HotSpot内部实现机制的同时,分析了HotSpot如此这般实现的技术必然性。读者在阅读《揭秘Java虚拟机:JVM设计原理与实现》的过程中,将会在很多地方看到作者本人的这种思考。
文件:590m.com/f/25127180-500695932-2e6ff3(访问密码:551685)
以下内容无关:
-------------------------------------------分割线---------------------------------------------
包含Dockerfile目录的所有内容称为上下文,上下文通过docker build命令传入到Docker daemon后,便开始按照Dockerfile中的内容一层层构造镜像。
为了提高镜像构建的速度,Docker daemon会缓存构建过程中的中间镜像。当从一个已在缓存中的基础镜像开始构建新镜像时,会将Dockerfile中的下一条指令和基础镜像的所有子镜像做比较,如果有一个子镜像是由相同指令生成的,则命中缓存,直接使用该镜像(COPY/ADD指令还会比较文件内容),一旦缓存失效,则后续的指令都将生成新的镜像,不在使用缓存。
2、Dockerfile指令
ENV
为镜像创建出来的容器声明环境变量,还可以被dockerfile后面的指令使用。
1
2
ENV
ENV
FROM
为后面的指令提供基础镜像,一个Dockerfile可以有多个FROM指令,这样会构建多个镜像。在每个镜像构建完成后,Docker命令行界面会输出该镜像的ID。
1
FROM :
COPY
复制文件或目录添加到新镜像中。
1
COPY
可以有多个,但必须是上下文根目录的相对路径,可以使用通配符。
可以是文件或目录(/结尾),但必须是目标镜像中的绝对路径或者相对于WORKDIR的相对路径。
ADD
和COPY一样,但可以是一个只想网络文件的URL
还可以只想本地的压缩归档文件,该文件复制到容器中时会被解压提取
RUN
在前一条命令创建的镜像基础上创建一个容器,并在容器中运行命令,命令结束后commit容器为新镜像,该镜像被Dockerfile中的下一条指令使用。
1
2
RUN (shell格式)
RUN [“executable”,“param1”,“param2”] (exec格式,推荐)
shell格式,命令通过/bin/sh -c运行。
exec格式,命令直接运行,参数会被当成JSON数组被Docker解析,所以必须使用双引号,因为exec不会在shell中执行,所以环境变量的参数不会被替换。例如当执行 CMD [“echo”,“ H O M E " ] 时 候 , HOME"]时候, HOME"]时候,HOME不会做变量的替换,可以改写为 CMD [“sh”,”-c",“echo”,"$HOME"]。
CMD
提供容器运行时的默认值,默认值可以是一条指令,可以是一些参数。
1
2
3
CMD (shell格式)
CMD [“executable”,“param1”,“param2”] (exec格式,推荐)
CMD [“param1”,“param2”] (为ENTRYPOINT指令提供参数)
一个Dockerfile中可以有多条CMD指令,但只有最后一条有效。
CMD vs RUN
RUN指令在构建镜像时执行命令,并生成新的镜像;CMD指令在构建镜像时并不执行命令,而是在容器启动时默认将CMD指令作为第一条执行的命令。
如果用户在命令行界面运行docker run命令时指定了命令参数,则会覆盖CMD指令中的命令。
ENTRYPOINT
和CMD类似,让容器在每次启动时候执行相同的命令。
1
2
ENTRYPOINT (shell格式)
ENTRYPOINT [“executable”,“param1”,“param2”] (exec格式,推荐)
一个Dockerfile中可以有多条ENTRYPOINT指令,但只有最后一条有效。
使用shell格式,ENTRYPOINT会忽略任何CMD指令和docker run命令参数,并且会运行在/bin/sh -c中,意味着该指令进程为/bin/sh -c的子进程,进程在容器中的PID不是1,且不能接受UNIX信号。即当使用docker stop 命令时,命令进程接收不到SIGTERM信号。
exec格式,docker run传入的参数会覆盖CMD指令的内容,但不会覆盖ENTRYPOINT
ONBUILD
添加一个将来执行的触发器指令到镜像中
3、实践心得
使用标签
1
docker build -t=“image:v1”
谨慎选择基础镜像
尽量选择官方镜像,linux镜像大小关系:busybox < debian < centos < ubuntu
构建镜像只安装使用必须的包。
FORM指令应该包含参数tag
充分利用缓存
Docker daemon会顺序执行Dockerfile中的指令,为了有效利用缓存,尽量将所有Dockerfile文件中相同的部分都放到前面,不同的部分放到后面。
正确使用ADD和COPY指令
首选COPY。
当在Dockerfile中的不同部分需要用到不同文件时,不要一次性地将这些文件都添加到镜像中去,而是在需要时候逐个添加,这样也有利于充分利用缓存。
考虑镜像大小问题,使用ADD获取远程URL压缩包不是推荐做法,应该使用RUN wget或RUN curl代替。
RUN指令
为了Dockerfile易读,使用比较长的RUN指令时可以使用\分隔多行。
不要在一行中单独使用RUN apt-get update。当软件源更新后,会引起缓存问题,导致RUN apt-get install失败。应该改为:RUN apt-get updata && apt-get install。
提交镜像是廉价的,不要害怕镜像的层数过多,因此,不要将所有命令写在一个RUN指令中。
不要在Dockerfile中做端口映射
使用EXPOSE指令会破坏Docker的可移植性
参考链接:
《Docker容器与容器云》