文档章节

漫谈JVM

liuzhengyang
 liuzhengyang
发布于 2016/10/05 13:24
字数 5302
阅读 7776
收藏 447
点赞 22
评论 10

背景介绍

JVM已经是Java开发的必备技能了,JVM相当于Java的操作系统。

JVM,java virtual machine, 即Java虚拟机,是运行java class文件的程序。

Java代码经过Java编译器编译,会编译成class文件,一种平台无关的代码格式,class文件按照jvm规范,包括了java代码运行所需的元数据和代码等内容。jvm加载class文件后,就可以执行java代码了。

JVM有不同的实现,有我们熟悉的Hotspot虚拟机,JRockit等。在各个操作系统上,又回有各自的虚拟机实现,从而形成了Java代码 > class文件 > JVM规范 > JVM实现的层次。再加上其他语言如scala、groovy也能够生成class文件,这样不仅实现了平台无关性,也实现了语言无关性。

JVM体系,分为JVM内存结构,Class文件结构,Java ByteCode,垃圾收集算法和实现,调优和监控工具,以及Java内存模型(JMM)。 jvm-mindmap

<!-- more -->

JVM内存结构

JVM-runtime-area

通常,认为大概分为线程共享的区域和线程私有的区域。共享区域在JVM启动时创建, 私有区域伴随这线程的启动和结束。

私有区域

一个线程拥有的结构有

程序计数器(Program Counter, PC)

Java天生支持多线程,多线程会有线程切换的问题,当一个线程从可运行状态得到CPU调度进入运行状态,CPU需要知道从哪里开始执行,并且Java是一种基于栈的执行架构(区别于基于寄存器的架构)。

当执行一个Java方法时,PC会指向下一条指令的位置。执行native方法时,PC是未定义。操作指令可能会有0个或多个操作数。JVM的执行流程大概可以描述为:

while(true) {
opcode = code[pc];
oprand = getOperan(opcode);
pc = code[pc + len(oprand)];
execute(opcode, oprand);
}

Java虚拟机栈(Java Virtual Machine Stack)

Java虚拟机栈,或者叫方法栈,会伴随这方法的调用和返回进行相应的入栈和出栈。栈的元素是栈帧(Stack Frame), 栈帧中的内容包括: 操作数栈,本地变量表,动态链接等信息。当线程调用一个方法的时候,会组装对应的栈帧入栈。

本地变量表(Local Variable Table)

本地变量表存储方法的参数、方法内部创建的局部变量。本地变量表的大小在编译时就确定了。本地变量表会根据变量的作用范围选择重用一个位置。本地变量表会存放 int,char,byte,float,double,long,address(实例引用)。其中除了double和long其他变量占用一个slot,一个slot指一个抽象的位置,在32位虚拟机中是32bit大小, double和long占用两个slot。 值得注意的时,如果一个方法是实例方法,Java编译器会将this作为第一个参数传入本地变量表。另外Java中面向对象,方法调用可以这样理解

实例方法
obj.method(var1, var2, var3) => method invoke obj var1 var2 var3

操作数栈

操作数栈用于方法内执行保存中间结果,Java方法中的代码逻辑就是通过操作数栈来实现的。和本地方法表一样,操作数栈也是在编译时就确定最大大小了,即最大深度。操作数栈可以和本地变量表交互,进行数据的存放和读取。下面用一个简单的例子展示一下。

int add(int a, int b) {
   return a + b;
}

这个实例方法经过Java编译器编译后生成的字节码

本地变量表
slot0  this 
slot1  a 
slot2  b

方法字节码
iload_1 #读位置是1的本地变量(本地变量表从0开始,位置0是this引用)
此时操作数栈是 a
iload_2 #读位置是2的本地变量,即b
此时操作数栈是 a b
iadd    #进行int类型的add操作,会取出栈头的两个元素取出进行相加并将结果入栈。
此时操作数栈是 c (相加的结果)
ireturn #ireturn指令会将栈头元素返回给调用方法的栈帧 

线程共享区域

堆(Heap区)

创建的对象(包括普通实例和数组)都分配在Heap区(不考虑一些虚拟机的栈上分配优化技术)。在细分的话,一般还分成年轻代和老年代。这是基于这样一个类似28原理的统计,90%多的对象都是很快成为垃圾的对象。所以化为成两个区域,分别使用不同的收集算法,年轻代的收集频率更高,所需空间也相对较小。内存分配时,多个线程会有并发问题,主要通过两种方式解决:1.CAS加上失败重试分配内存地址。2. TLAB, 即Thread Local Allocation Buffer, 为每个线程分配一块缓冲区域进行对象分配。年轻代还可以分为两个大小相等的Survivor和一个Eden区域。对象在几种情况下会进入老年代:1. 大对象,超过Eden大小或者PretenureSizeThreshold. 2. 在年轻代的年龄(经历的GC次数)超过设定的值的时候 3. To Survivor存放不下的对象

方法区

方法区存放加载的类信息和运行时常量池等。

垃圾收集(Garbage Collect)

在Java应用中不需要也不能通过代码对内存进行手动释放,JVM中的垃圾器帮助我们自动回收没有程序引用的对象。除了进行内存释放,JVM还需对内存进行整理,因为有内存碎片的问题。GC的优点是加快开发效率,不需要关心内存释放,并且避免了很多内存安全问题。缺点是会带来性能损耗。 GC必须要做两件事情,找出垃圾对象和回收它们的内存。

何时进行收集

一般来说,当某个区域内存不够的时候就会进行垃圾收集。如当Eden区域分配不下对象时,就会进行年轻代的收集。还有其他的情况,如使用CMS收集器时配置CMSInitiatingOccupancyFraction设置什么时候触发Old区的回收。

如何判断一块内存是垃圾

即判断一个对象不再使用,不再使用可以是没有有效的引用。 一般来说,主要有两种判断方式

引用计数(Reference Count)

当有对象引用自身时,就会计数器加1,删除一个引用就减一,当计数为0时即可判断为垃圾。python等语言使用引用计数。引用计数存在循环引用问题,如两个落单的A和B互相引用,但是没有其他对象指向它们这种情况.

可达性分析(Reachability Analysis)

通过一些根节点开始,分析引用链,没有被引用的对象都可以被标记为垃圾对象。根节点是方法栈中的引用、常量等。根节点集合和具体的实现相关,但是会包括: 线程栈帧中的本地变量和操作数栈中的对象引用,静态变量、常量以及已经加载的类的常量池中的队形引用等。所有能够通过引用链引用到的对象都被认为是活对象。 JVM中普遍使用的是可达性分析。

垃圾收集算法

标记清除(Mark Sweep)

对非垃圾对象进行标记都,清除其他的对象。这种方式对对内存空间造成空隙,即内存碎片,最终导致有空余空间,但没有连续的足够大小的空间分配内存。

标记整理(Mark Compact)

标记非垃圾对象后,将这些对象整理好,依次排列内存。这样内存就是整齐的了。但是因为会造成对象移动,所以效率会有降低。

标记清除整理(Mark Sweep Compact)

即组合两种方式,在若干次清除后进行一次整理。

复制(Copy)

划分成两个相同大小的区域,收集时,将第一个区域的活对象复制到另一个区域,这样不会有内存碎片问题。但是最多只能存放一半内存,而且所有的活对象都需要拷贝。

Sun HotSpot虚拟机

为了保证实际GC过程中对象的一致性,GC往往需要停顿所有的Java应用线程,也就是常说的StopTheWorld。 目前主流的虚拟机可以知道哪个位置保存着对象引用,在HotSpot中,通过OopMap的数据结构在快速的GC Root枚举。 安全点(Safe Point): 程序并非在所有时刻都能停顿下来开始GC,只有到达安全点才能暂停。安全点知识程序可能长时间执行的可能的指令,例如方法调用、循环跳转、异常跳转等。发生GC时需要让所有线程停下来,有抢先式中断和主动式中断两种方式。为了解决主动式中断线程一直不响应中断请求的问题,又引入了安全区域(Safe Region)的概念,安全区域是在一段代码片段之中引用关系不会发生变化,线程离开安全区域时,要检查系统是否已经完成了根节点枚举,如果没有则一直等待。

垃圾收集器

垃圾收集器就是垃圾收集算法的相应实现。 在大多数的应用中,有基本能统计到以下的现象:

  • 大多数的对象都是短命的对象
  • 大多数的程序会创建一些长时间存活的对象 所以经常会将内存区域划分成两部分,每个部分各自使用合适的收集算法,也就是分代收集。通过记录对象的年龄(经历过的GC次数), 年轻代进行的收集更频繁,对象到达一定年龄后进入老年代。

Serial New

新生代单线程的收集器,是Client模式默认的垃圾收集器

Parallel New

Serial New的多线程版本。ParNew常和CMS拉配使用。这里说明一些Parallel和Concurrent即并行和并发在垃圾收集这里的表示的不同,并行表示有多个线程同时进行垃圾收集,并发是指垃圾收集线程和应用线程可以并发执行。

Parallel Scanvenge

PS收集器是注重吞吐量(ThroughPut)的收集器。

Serial Old。

老年代的单线程收集器

Parallel Old

Serial Old的多线程版本,由于Parallel Scavenge不能和CMS搭配使用,所以会是使用PS时的一种选择。

CMS (Concurrent Mark Sweep)

注重延迟latency的收集器,在交互式应用中,如面向用户的web应用,需要尽可能减少垃圾收集造成的停顿时间。在总的统计上,吞吐量可能没有PS收集器高。 细分上,CMS还分为4个阶段

  • 初始标记,标记GC Root可以直达的对象。STW
  • 并发标记,从第一步标记的对象开始,进行可达性分析遍历,和应用线程并发执行。
  • 重新标记,SWT,修正上一阶段并发执行造成的引用变化。
  • 并发清除,并发的清除垃圾 CMS使用标记清除算法,所以有内存碎片问题,可能设置参数在进行若干次不带整理的收集后进行一次带整理(compact)的收集。另外,因为垃圾收集是和应用线程并发执行的,在收集的同时可能还会有垃圾不断产生,即产生了浮动垃圾。另外还需要预留出一定空间,到达这个值后进行收集,但是还会有收集速度赶不上生产的速度,这时就会出现Concurrent Mode Failure,CMS会退化成Serial Old进行GC。

G1 (Garbage First)

具有大内存收集和目标效率时间等控制能力,目标是代替CMS。G1通过将内存划分成不同的区域(Region),并对不同区域计算分数,分析那个Region最具有收集价值。

一些JVM的GC参数

常用的参数设置有

  • -Xms=4g -Xmx=4g 设置Java堆的初始大小和最大大小均为4g,即避免了堆大小调整
  • -Xmn=1g 设置年轻代的总大小为1g
  • -SurvivorRatio=8, 设置Eden和一个Survivor的比例为8:1
  • -XX:+PringGCDetails

堆外内存(Non Heap)

Nio中的DirectByteBuffer就是堆外内存的一部分,这部分内存只能通过Full Gc进行清理。一些框架会通过System.gc调用手动触发gc,但是在启动参数中可能设置了禁止调用System.gc()。另外当设置堆过大时可能会造成堆外内存不够导致OOM。

监控工具

监控工具帮助我们在运行时或问题发生后分析现场,分析内存分布状态,哪里导致内存泄漏等(本该被释放的对象仍然被引用)。

命令行工具

HotspotJVM的bin目录下有很多可用的工具。

jps

jps
jps -l
jps -lv

即java版的ps,可以查看当前用户启动了哪些java进程。

jstat

pid指jps命令查看的java进程号

jstat -gcutil pid 1000 10 

jstat是一个多种用途的工具,更多需要man jstat或直接输入jstat查看提示。

jmap

jmap可以查看内存状况

jmap -histo:live pid
jmap -dump:file=dump.bin,format=b,live
jmap -dump:file=dump.bin,format=b
dump下来的内存文件可以通过MAT进行分析,通过分析引用链等分析内存泄漏位置

jstack

查看Java线程状况

jstack pid
jstack -F pid
可以查看线程的状态、名称、代码位置

javap (Java Printer)

javap 可以用可读的方法查看class文件内容,在遇到线上class文件问题,如NoSucheMethodError发生时,可以快速进行判断分析。如分析一个A.class文件,查看它的私有方法和字段。

javap -p -c -v A.class

可视化工具

JVisualVM

$JAVA_HOME/bin/jvisualvm

JMC

$JAVA_HOME/bin/jmc

JConsole

$JAVA_HOME/bin/jconsole

Class文件结构

Java编译器将Java代码编译成class文件格式。 其中步骤包括了我们熟悉的词法分析将源文件转换成token流。语法分析将token流转换成抽象语法树(AST)。语义分析分析语义是否正确。源代码优化。目标代码生成和目标代码优化等步骤。最终得到了class文件。之后在虚拟机中,class文件可以通过解释器解释执行和通过即时编译器(JIT-just in time)编译成native代码执行两种方式执行。 class文件是有严格定义的。符合定义的class文件才能够被JVM加载、验证、初始化、执行。 我们通过javap可以查看一个class文件的内容。 Class文件可以分为以下几个部分

  • Magic Number (0xCAFEBABY)
  • minor version, major version 如 0x0033 代表 00,51, 是java8版本
  • constant pool 常量池,常量池中包括了字段、方法、类的名称的符号引用,符号引用会在运行时经过链接转换为直接引用。
  • access flags 类的private、public等修饰词
  • this class 表明当前类的名称
  • super class 父类
  • interfaces 实现的接口列表
  • fields class中定义的字段,每个field又是一个结构体
  • methods 方法,包括MaxLocal, Max Stack,方法名,signature,access flags等。 代码保存在方法的名称为Code的属性中。
  • attributes

下面以一个简单的类

public class Inc {
    public static void main() {
    }

    private int count;
    public void inc() {
        count++;
    }
}

看一下它的class文件,通过vim打开,在Normal模式下,按: 输入%!xxd,即可转换成16进制表示。然后可以通过%!xxd -r转换回来

0000000: cafe babe 0000 0034 0013 0a00 0400 0f09  .......4........
0000010: 0003 0010 0700 1107 0012 0100 0563 6f75  .............cou
0000020: 6e74 0100 0149 0100 063c 696e 6974 3e01  nt...I...<init>.
0000030: 0003 2829 5601 0004 436f 6465 0100 0f4c  ..()V...Code...L
0000040: 696e 654e 756d 6265 7254 6162 6c65 0100  ineNumberTable..
0000050: 046d 6169 6e01 0003 696e 6301 000a 536f  .main...inc...So
0000060: 7572 6365 4669 6c65 0100 0849 6e63 2e6a  urceFile...Inc.j
0000070: 6176 610c 0007 0008 0c00 0500 0601 0003  ava.............
0000080: 496e 6301 0010 6a61 7661 2f6c 616e 672f  Inc...java/lang/
0000090: 4f62 6a65 6374 0021 0003 0004 0000 0001  Object.!........
00000a0: 0002 0005 0006 0000 0003 0001 0007 0008  ................
00000b0: 0001 0009 0000 001d 0001 0001 0000 0005  ................
00000c0: 2ab7 0001 b100 0000 0100 0a00 0000 0600  *...............
00000d0: 0100 0000 0100 0900 0b00 0800 0100 0900  ................
00000e0: 0000 1900 0000 0000 0000 01b1 0000 0001  ................
00000f0: 000a 0000 0006 0001 0000 0003 0001 000c  ................
0000100: 0008 0001 0009 0000 0027 0003 0001 0000  .........'......
0000110: 000b 2a59 b400 0204 60b5 0002 b100 0000  ..*Y....`.......
0000120: 0100 0a00 0000 0a00 0200 0000 0700 0a00  ................
0000130: 0800 0100 0d00 0000 0200 0e0a            ............

通过javap来看一下它的结构

javap -v -p -c -s -l Inc
Classfile /Users/liuzhengyang/study/java/Inc.class
  Last modified Oct 6, 2016; size 315 bytes
  MD5 checksum 770dcaa972162765744184ffc14bc3c6
  Compiled from "Inc.java"
public class Inc
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #4.#15         // java/lang/Object."<init>":()V
   #2 = Fieldref           #3.#16         // Inc.count:I
   #3 = Class              #17            // Inc
   #4 = Class              #18            // java/lang/Object
   #5 = Utf8               count
   #6 = Utf8               I
   #7 = Utf8               <init>
   #8 = Utf8               ()V
   #9 = Utf8               Code
  #10 = Utf8               LineNumberTable
  #11 = Utf8               main
  #12 = Utf8               inc
  #13 = Utf8               SourceFile
  #14 = Utf8               Inc.java
  #15 = NameAndType        #7:#8          // "<init>":()V
  #16 = NameAndType        #5:#6          // count:I
  #17 = Utf8               Inc
  #18 = Utf8               java/lang/Object
{
  private int count;
    descriptor: I
    flags: ACC_PRIVATE

  public Inc();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=1, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: return
      LineNumberTable:
        line 1: 0

  public static void main();
    descriptor: ()V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=0, locals=0, args_size=0
         0: return
      LineNumberTable:
        line 3: 0

  public void inc();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=3, locals=1, args_size=1
         0: aload_0
         1: dup
         2: getfield      #2                  // Field count:I
         5: iconst_1
         6: iadd
         7: putfield      #2                  // Field count:I
        10: return
      LineNumberTable:
        line 7: 0
        line 8: 10
}
SourceFile: "Inc.java"

字节码指令集

bytecode保存在class文件的方法的Code属性中。用一个byte表示操作指令,所以最多有256个指令。一个指令可能会有多个操作数。 操作指令可以分为以下几类:

  • 数学运算,如iadd,i2c,imul,idiv
  • 条件分支, 如ifeq,if_icompeq, if_icmplt
  • 操作数栈和本地变量表的操作,如iload_0, iconst_0, ldc i bipush 100, astore_1, iinc, dup, swap, dup_x1,put_field, get_field, get_static, put_static等。
  • class操作,如new, checkcast, instanceof
  • 方法调用:1.invokespecial:调用构造器、私有方法和父类方法;2.invokestatic:调用静态方法;3.invokevirtual:调用虚方法,一般的实例方法都是invokevirtual调用;4.invokeinterface:调用接口类的方法;5.invokedynamic,java中对动态语言的支持。 invokevirtual和invokeinterface通过第一个参数查找方法,动态分派,从而实现多态。

JMM (Java内存模型)

现代计算机的一本基本思想是分层模型,例如网络上的分层。在存储上,为解决CPU和内存磁盘的速度有指数级差别的问题加入了很多缓存,利用局部性原理加快速度,从CPU寄存器到L1Cache、L2Cache、内存、磁盘,各个层的速度依次降低、空间增大、单位bit造价降低。最近CPU的处理能力的垂直增加似乎遇到瓶颈,转而向多核方向发展,多个cpu核可能各自缓存自己的内容,又出现了缓存一致性问题。CPU有一些缓存一致性协议,MESI等。CPU还可能会对机器指令进行乱序执行。JVM为了屏蔽底层的这些差异,提出了Java内存模型,即JMM(Java Memory Model),来保证Write One Run Anywhere。开发者面向JMM编程,通过JMM提供的一致性保证和工具,就能保证一致性问题。 JMM模型中,每个线程会有一个私有的内存区域用于缓存读和写,各个线程共享一个主内存。 一个重要的概念是happen-before原则。 happen-before用来描述两个操作的偏序关系,如果Ahappen-beforeB,那个A的操作的结果、产生的影响能够被B看到。 如果我们有两个动作x和y,我们记hb(x,y)为x happen before y JMM提供的基础的happen-before规则有

  • 同一个线程内,x在y前面,则hb(x,y)
  • 如果hb(x,y) 并且 hb(y, z) ,则 hb(z,z)
  • 一个监视器锁的unlock happen before 之后每一个对该监视器的lock
  • 一个volatile字段 写操作 happen before 之后的每一个读
  • 一个线程的start操作happen-before 线程内的任何操作
  • 线程内的任何操作都happen-before 任何从该线程的join()方法返回的

happen-before并不要求在之前发生,只需能够看到操作的结果即可,对应的实现可以进行重排序或消除锁,只要保证外观正确。

最后总结

以上的总结梳理权当抛砖引入,帮助大家梳理知识结构,更多细节还需通过查看源码、亲自探索,真像就在那代码中。而且每个知识点又能够引出一篇笔记分析,之后后补充更多细节文章。

参考

  • JLS
  • JVMS
  • 深入理解Java虚拟机
  • Inside The Java Virtual Machine

博客地址: liuzhengyang

© 著作权归作者所有

共有 人打赏支持
liuzhengyang

liuzhengyang

粉丝 52
博文 17
码字总数 15932
作品 2
海淀
程序员
加载中

评论(10)

为为02
为为02
学习了,先收藏
FantasyBabymg
FantasyBabymg
不错 用来回顾和理清结构都很有帮助 感谢(途中有点错别字,不过无伤大雅)。
liuzhengyang
liuzhengyang

引用来自“bosszhou”的评论

JVM内存结构图片--> 本地房发展
:thumbsup:修改过来了
梦中一点心雨
梦中一点心雨
不错,能涉及关于jvm缓存的东西吗?
bosszhou
bosszhou
JVM内存结构图片--> 本地房发展
liuzhengyang
liuzhengyang

引用来自“宇林木风”的评论

总体不错,在何时进行垃圾收集那节希望能深入一点,实际上那里有一些量化指标的。
多谢指点,会继续补充的
k
koner
完全看不懂
天空矿工
不是写明是漫谈吗zbg
宇林木风
总体不错,在何时进行垃圾收集那节希望能深入一点,实际上那里有一些量化指标的。
Qiujuer
Qiujuer
总结的挺不错的,每个知识点都有一些总结,虽然不够详细,但是拉通思路是非常不错的。
CentOS 6.5 安装JDK(包含卸载原有默认JDK)

卸载原有1.7 JDK 查看是否安装了JDK 若有内容就进一步查看JDK信息 卸载 安装jdk ===================================== 安装wget 新建目录 进入目录 下载JDK 安装JDK 配置环境变量 往文件内...

阿白 ⋅ 05/23 ⋅ 0

Java就业变难了?你需要对自己有点信心

伴随着IT的火热,越来越多的人进入了IT领域,这在进一步推动着IT发展的同时也极大增加了就业压力。伴随着激烈的岗位竞争,越来越多的人开始感叹工作难找,越火的行业越是如此,Java自是首当其...

糖宝_d864 ⋅ 06/08 ⋅ 0

sharding-jdbc源码分析—准备工作

原文作者:阿飞Javaer 原文链接:https://www.jianshu.com/p/7831817c1da8 接下来对sharding-jdbc源码的分析基于tag为源码,根据sharding-jdbc Features深入学习sharding-jdbc的几个主要特性...

飞哥-Javaer ⋅ 05/03 ⋅ 0

MVN package install error javac: invalid target release: 1.8

现象: --------------------------------- [ERROR] Failure executing javac, but could not parse the error: javac: invalid target release: 1.8 Usage: javac <options> <source files>......

孟飞阳 ⋅ 05/04 ⋅ 0

Oracle Java Mission Control 帮助

缩写 含义 JDK Java 开发工具包 JDP Java Discovery Protocol JFR Java 飞行记录器 JMC Java Mission Control JMX Java Management Extensions JVM Java 虚拟机 MBean 托管 Bean (Java) RCP ......

光斑 ⋅ 04/27 ⋅ 0

培训云计算学校,虚拟机基本结构讲解

我们要对JVM虚拟机的结构有一个感性的认知。毕竟我们不是编程人员,认知程度达不到那么深入。一个运行时的Java虚拟机实例的天职是:负责运行一个java程序。当启动一个Java程序时,一个虚拟机...

长沙千锋 ⋅ 05/17 ⋅ 0

云计算高级培训,Tomcat运维JVM 虚拟机常识

云计算高级培训,Tomcat运维JVM 虚拟机常识,作为了解JVM 虚拟机的开始。我们很有必要弄明白以下问题。 所谓虚拟机,就是一台虚拟的计算机。他是一款软件,用来执行一系列虚拟计算机指令。大...

长沙千锋 ⋅ 05/17 ⋅ 0

14、Java并发性和多线程-Java ThreadLocal

以下内容转自http://ifeve.com/java-theadlocal/: Java中的ThreadLocal类可以让你创建的变量只被同一个线程进行读和写操作。因此,尽管有两个线程同时执行一段相同的代码,而且这段代码又有...

easonjim ⋅ 2017/06/16 ⋅ 0

centos6.5 安装jdk1.8

第一种方式: 使用yum命令安装,这样安装的好处就是不用配置环境变量!! 可以看到yum 库中的jdk版本这里选择 安装jdk 如果你安装jdk1.7 就改成java-1.7.0-openjdk 表示安装成功了!! jdk安...

jason_kiss ⋅ 昨天 ⋅ 0

Java开发学习之三版本简介 java编程

  Java编程语言,在更迭迅速的互联网领域多年屹立不倒,足以得见Java这门语言旺盛的生命力,因此,会有很多想要进入互联网领域的朋友,想要学Java来转行开发。但是,所谓“隔行如隔山”,j...

老男孩Linux培训 ⋅ 06/05 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

十五周二次课

十五周二次课 17.1mysql主从介绍 17.2准备工作 17.3配置主 17.4配置从 17.5测试主从同步 17.1mysql主从介绍 MySQL主从介绍 MySQL主从又叫做Replication、AB复制。简单讲就是A和B两台机器做主...

河图再现 ⋅ 45分钟前 ⋅ 0

docker安装snmp rrdtool环境

以Ubuntu16:04作为基础版本 docker pull ubuntu:16.04 启动一个容器 docker run -d -i -t --name flow_mete ubuntu:16.04 bash 进入容器 docker exec -it flow_mete bash cd ~ 安装基本软件 ......

messud4312 ⋅ 今天 ⋅ 0

OSChina 周一乱弹 —— 快别开心了,你还没有女友呢。

Osc乱弹歌单(2018)请戳(这里) 【今日歌曲】 @莱布妮子 :分享吴彤的单曲《好春光》 《好春光》- 吴彤 手机党少年们想听歌,请使劲儿戳(这里) @clouddyy :小萝莉街上乱跑,误把我认错成...

小小编辑 ⋅ 今天 ⋅ 7

mysql in action / alter table

change character set ALTER SCHEMA `employees` DEFAULT CHARACTER SET utf8mb4 DEFAULT COLLATE utf8mb4_general_ci ;ALTER TABLE `employees`.`t2` CHARACTER SET = utf8mb4 , COLLAT......

qwfys ⋅ 今天 ⋅ 0

Java 开发者不容错过的 12 种高效工具

Java 开发者常常都会想办法如何更快地编写 Java 代码,让编程变得更加轻松。目前,市面上涌现出越来越多的高效编程工具。所以,以下总结了一系列工具列表,其中包含了大多数开发人员已经使用...

jason_kiss ⋅ 昨天 ⋅ 0

Linux下php访问远程ms sqlserver

1、安装freetds(略,安装在/opt/local/freetds 下) 2、cd /path/to/php-5.6.36/ 进入PHP源码目录 3、cd ext/mssql进入MSSQL模块源码目录 4、/opt/php/bin/phpize生成编译配置文件 5、 . ./...

wangxuwei ⋅ 昨天 ⋅ 0

如何成为技术专家

文章来源于 -- 时间的朋友 拥有良好的心态。首先要有空杯心态,用欣赏的眼光发现并学习别人的长处,包括但不限于工具的使用,工作方法,解决问题以及规划未来的能力等。向别人学习的同时要注...

长安一梦 ⋅ 昨天 ⋅ 0

Linux vmstat命令实战详解

vmstat命令是最常见的Linux/Unix监控工具,可以展现给定时间间隔的服务器的状态值,包括服务器的CPU使用率,内存使用,虚拟内存交换情况,IO读写情况。这个命令是我查看Linux/Unix最喜爱的命令...

刘祖鹏 ⋅ 昨天 ⋅ 0

MySQL

查看表相关命令 - 查看表结构    desc 表名- 查看生成表的SQL    show create table 表名- 查看索引    show index from  表名 使用索引和不使用索引 由于索引是专门用于加...

stars永恒 ⋅ 昨天 ⋅ 0

easyui学习笔记

EasyUI常用控件禁用方法 combobox $("#id").combobox({ disabled: true }); ----- $("#id").combobox({ disabled: false}); validatebox $("#id").attr("readonly", true); ----- $("#id").r......

miaojiangmin ⋅ 昨天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部