入门小站

入门小站 查看完整档案

填写现居城市  |  填写毕业院校  |  填写所在公司/组织填写个人主网站
编辑

rumenz.com

个人动态

入门小站 发布了文章 · 10月26日

JVM判断对象是否存活

  • 引用计数法
  • 可达性分析算法

引用计数法

给对象添加一个引用计数器,每当有一个地方引用,计数器就加1,当引用失效,计数器减1,计数器为0的对象没有被使用,Java中没有使用引用计数法,原因是引用计数法无法解决对象间的循环引用问题。

package com.rumenz;
public class Testy {
    public Object instance = null;
    public static void main(String[] args) throws InterruptedException {
        Testy objA = new Testy();
        Testy objB = new Testy();
        objA.instance = objB;
        objB.instance = objA;
        objA = null;
        objB = null;
        //假设在这行发生了gc,objA和objB是否被回收
        System.gc();
        //拖延时间查看堆内存对象
        Thread.sleep(50000);
    }
}

VM设置参数

-XX:+PrintGCDetails -XX:-UseAdaptiveSizePolicy -XX:SurvivorRatio=8 -XX:NewSize=10M -XX:MaxNewSize=10M

-XX:+PrintGCDetails 启用日志
-XX:-UseAdaptiveSizePolicy 禁用动态调整,使SurvivorRatio可以起作用
-XX:SurvivorRatio=8 设置Eden:Survivior=8
-XX:NewSize=10M -XX:MaxNewSize=10M 设置整个新生代的大小为10M

使用jmap -histo pid查看堆内的对象

断开栈和堆对象的引用

objA = null;
objB = null;

jmap -histo pid

堆中未发现com.rumenz.Testy对象。虽然objAobjB存在相互引用,但是由于栈和堆对象没有了引用关系, 垃圾回收时将objAobjB回收掉,说明JVM虚拟机未使用引用计数法来判断对象是否存活。

未断开栈和堆对象的引用

//objA = null;
//objB = null;

jmap -histo pid

堆中发现com.rumenz.Testy对象。因为对象还在使用着。

可达性分析算法

GC Root对象为起点,从这些对象为起点,往下搜索,走过的路径为引用连,当一个对象到GC Roots没有任何引用连引用,则证明此对象没有被用到,将会被JVM判定为垃圾。

img

JDK1.8中什么是GC Root

  • 虚拟机栈中(栈帧中的本地变量表)中引用的对象。
  • 元数据区类静态属性引用的对象
  • 元数据区常量引用的对象
  • 本地方法栈(Native)方法引用的对象

相对于引用计数法,可达性分析避免了循环导致的问题。同时具备执行搞笑的特点。也是JVM采用的标记算法。

查看原文

赞 0 收藏 0 评论 0

入门小站 发布了文章 · 10月23日

JAVA的对象访问定位

创建对象是为了访问对象,Java程序通过栈的引用(reference)数据来操作堆上的对象。由于reference类型在Java虚拟机规范中只规定了一个指向对象的引用。并没有规定通过该引用怎么定位,访问堆中的对象。具体需要看虚拟机的实现。

两种访问方式:

  • 句柄访问
  • 直接访问

句柄访问

Java堆中会划分一个句柄池,reference存储的就是对象的句柄地址,而句柄中存放的是对象的实例数据和类型数据的地址信息。

image-20201023232424966

直接访问

Java堆对象布局就必须考虑如何存放访问类型数据的相关信息,reference存储的就是对象的地址。

image-20201023232718060

句柄访问和直接访问的特点

  • 句柄访问:reference存放的是句柄地址(比较稳定),在对象移动时(垃圾回收),只会改变句柄中实例数据的地址,而reference无需改变。
  • 直接访问:由于节省了一次指针开销访问速度比较快,由于对象的访问在Java堆上访问特别频繁。Sun HotSpot虚拟机采用的是直接访问。

查看原文

赞 0 收藏 0 评论 0

入门小站 发布了文章 · 10月21日

JVM内存模型

总览

image-20201021222746282

JVM标准中的五个组成部分

  • 方法区
  • 程序计数器
  • 本地方法栈
  • 虚拟机栈

JDK1.7的运行时数据区

image-20201021224100216

  • 永久代是方法区的实现
  • jdk1.6之前字符串常量池在方法区
  • jdk1.7之后字符串常量池被移动到堆区

JDK1.8的运行时数据区

image-20201021224342226

  • jdk1.8去掉了永久代
  • 引入了元数据区
  • Jdk1.7中的运行时常量池移动到元数据区
  • 元数据区存在于直接内存中

为什么移除永久代

方法区大小难以设定,容易发生内存溢出。永久代存放着Class相关信息,一般信息在编译期就能确定,但是如果在一些动态生成的Class的应用中,如:Spring中的动态代理,大量的JSP页面或动态生成的JSP页面,由于方法区在一开始就要分配好,因此难以确定大小,容易发生内存溢出。
GC复杂效率低,方法区存放元数据和各种常量,但是这些数据被类的实例所引用,导致垃圾回收非常困难.
促进HotSpot VM和JRockit VM融合,JRockit VM没有方法区

什么是元空间

元空间永久代类似都是对JVM规范中方法区的实现。区别在于元空间不在JVM虚拟机中,因此元空间的空间受本地内存制约。

元空间特点

  • 每个加载器都有自己的空间
  • 不会单独回收某个类
  • 元空间对象的位置是固定的
  • 如果发现某个加载器不在存活,则将整个空间回收

image-20201021232107384

查看原文

赞 0 收藏 0 评论 0

入门小站 发布了文章 · 10月19日

JVM程序计数器,虚拟机栈,本地方法栈

程序计数器

它记录了程序执行字节码的行号和指令,字节码解释器的工作就是改变程序计数器的值,切换下一条需要执行的指令(分支,循环,跳转,异常等)。java虚拟机是多线程通过轮流切换CPU时间片的方式实现,在同一时间内,CPU只会执行一个线程中的一个指令,为了每次切换回来都能到正确的执行位置,每个线程都会有一个独立的线程计数器,每个计数器不会相互影响,并且是线程私有的。由于不是开发者操作,所以是不会产生异常的。

虚拟机栈

虚拟机栈也是线程私有的,它的声明周期与线程一样(和线程同生死)。如果线程请求栈的深度大于虚拟机所允许的深度则会报错StackOverFlow的错误。如果虚拟机可以动态扩展,如果扩展后无法获得到内存,就会报错OutOfMemoryError。java虚拟机栈描述的是Java方法执行的内存模型,每个方法执行的同时都会创建一个栈帧,对于我们来说主要关注栈内存,也是方法内的局部变量。

栈帧

栈帧虚拟机进行方法调用和方法执行的数据结构,它是虚拟机运行时数据区虚拟机栈的栈元素。栈帧存储了方法的局部变量表,操作数栈,动态链接和方法返回地址信息。在程序编译期,栈帧需要多大的局部变量表内存,多深的操作数栈已经确定。在活动线程中,栈顶的栈帧才是有效的,与这个栈帧关联的方式是当前方法,执行引擎运行的所有字节码指令都只会作用于当前栈帧。

img

本地方法栈

本地方法栈和虚拟机栈发挥的作用基本一样。区别是:本地方法栈执行的是Native方法服务,而虚拟机栈执行的是java方法。在HotSpot vm中本地方法栈和虚拟机栈合二为一。

img

注意:

当一个线程调用本地方法时,就会进入了一个不受java虚拟机限制的世界,它和虚拟机有着同样的权限。本地方法可以通过本地接口访问虚拟机运行时数据区。它可以直接使用本地处理器的寄存器。并不是所有的JVM都支持本地方法。如果JVM产品不打算支持Native方法,也可以不用实现本地方法栈。

查看原文

赞 0 收藏 0 评论 0

入门小站 发布了文章 · 10月18日

JVM常量池

image-20201017230142565

Class文件常量池

class文件是以字节为单位的二进制数据流,java编译器将java源码文件编译成.class字节码文件存放在磁盘上,.class中就包含文件常量池(非运行时常量池),在编译期间就确定了,.class文件遵循jvm虚拟机规范.

Java源码:

package com.rumenz;

public class rumenz{
      public Integer id=10;
      public String  name="入门";
      public final int  age=100;
      public void setId(Integer id){
          this.id=id;
      }
}

查看字节码

> javac rumenz.java
> javap -v rumenz
警告: 二进制文件rumenz包含com.rumenz.rumenz
Classfile /code/rumenz.class
  Last modified 2020-10-17; size 542 bytes
  MD5 checksum 6a8a73fb6327c1a64e9ad54e53e94afd
  Compiled from "rumenz.java"
public class com.rumenz.rumenz
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #9.#24         // java/lang/Object."<init>":()V
   #2 = Fieldref           #8.#25         // com/rumenz/rumenz.id:I
   #3 = String             #26            // 入门
   #4 = Fieldref           #8.#27         // com/rumenz/rumenz.name:Ljava/lang/String;
   #5 = Methodref          #28.#29        // java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
   #6 = Fieldref           #8.#30         // com/rumenz/rumenz.age:Ljava/lang/Integer;
   #7 = Methodref          #28.#31        // java/lang/Integer.intValue:()I
   #8 = Class              #32            // com/rumenz/rumenz
   #9 = Class              #33            // java/lang/Object
  #10 = Utf8               id
  #11 = Utf8               I
  #12 = Utf8               name
  #13 = Utf8               Ljava/lang/String;
  #14 = Utf8               age
  #15 = Utf8               Ljava/lang/Integer;
  #16 = Utf8               <init>
  #17 = Utf8               ()V
  #18 = Utf8               Code
  #19 = Utf8               LineNumberTable
  #20 = Utf8               setId
  #21 = Utf8               (Ljava/lang/Integer;)V
  #22 = Utf8               SourceFile
  #23 = Utf8               rumenz.java
  #24 = NameAndType        #16:#17        // "<init>":()V
  #25 = NameAndType        #10:#11        // id:I
  #26 = Utf8               入门
  #27 = NameAndType        #12:#13        // name:Ljava/lang/String;
  #28 = Class              #34            // java/lang/Integer
  #29 = NameAndType        #35:#36        // valueOf:(I)Ljava/lang/Integer;
  #30 = NameAndType        #14:#15        // age:Ljava/lang/Integer;
  #31 = NameAndType        #37:#38        // intValue:()I
  #32 = Utf8               com/rumenz/rumenz
  #33 = Utf8               java/lang/Object
  #34 = Utf8               java/lang/Integer
  #35 = Utf8               valueOf
  #36 = Utf8               (I)Ljava/lang/Integer;
  #37 = Utf8               intValue
  #38 = Utf8               ()I
{
  public int id;
    descriptor: I
    flags: ACC_PUBLIC

  public java.lang.String name;
    descriptor: Ljava/lang/String;
    flags: ACC_PUBLIC

  public final java.lang.Integer age;
    descriptor: Ljava/lang/Integer;
    flags: ACC_PUBLIC, ACC_FINAL

  public com.rumenz.rumenz();
    descriptor: ()V
    flags: ACC_PUBLIC
    Code:
      stack=2, locals=1, args_size=1
         0: aload_0
         1: invokespecial #1                  // Method java/lang/Object."<init>":()V
         4: aload_0
         5: bipush        10
         7: putfield      #2                  // Field id:I
        10: aload_0
        11: ldc           #3                  // String 入门
        13: putfield      #4                  // Field name:Ljava/lang/String;
        16: aload_0
        17: bipush        100
        19: invokestatic  #5                  // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
        22: putfield      #6                  // Field age:Ljava/lang/Integer;
        25: return
      LineNumberTable:
        line 11: 0
        line 12: 4
        line 13: 10
        line 14: 16

  public void setId(java.lang.Integer);
    descriptor: (Ljava/lang/Integer;)V
    flags: ACC_PUBLIC
    Code:
      stack=3, locals=3, args_size=2
         0: aload_0
         1: iconst_3
         2: aload_1
         3: invokevirtual #7                  // Method java/lang/Integer.intValue:()I
         6: iadd
         7: putfield      #2                  // Field id:I
        10: return
      LineNumberTable:
        line 17: 0
        line 18: 10
}
SourceFile: "rumenz.java"

什么是常量

文本字面量

#29 = Utf8 入门

final修饰成员变量(静态变量,实例变量,局部变量)

对于基本类型public Integer id=10;常量池中只保留了他的字段描述符I和字段名称value,他们的字面量不会存在于常量池。

符号引用

符号引用主要设涉及编译原理方面的概念,包括下面三类常量:
  • 类和接口的全限定名,也就是java/lang/String,将原来的.替换成/,主要用于在运行时解析得到类的直接引用。
#8 = Class              #32            // com/rumenz/rumenz
  • 字段的名称和描述符:就是类或者接口中声明的变量,包括类级别的变量和实例级的变量
#14 = Utf8               age
  • 方法中的名称和描述符:参数类型+返回值
 #20 = Utf8              setId

运行时常量池

运行时常量池是方法区的一部分,所以也是全局共享的,JVM在执行某个类的时候会经过加载,链接(验证,准备,解析),初始化,在加载的时候需要做:
  • 通过一个类的全类限定名获取此类的二进制字节流。
  • 在堆内存生成一个java.lang.Class对象,代表加载这个类,做为这个类的入口。
普通对象类对象的区别:普通对象是通过new创建出来的。类对象是JVM创建的单例对象。
  • 将字节流的静态存储结构转化成方法区的运行时数据结构
class文件常量池进入运行时常量池,所有类共同使用一个运行时常量池,在进入运行时常量的过程中,多个class常量池中相同的字符串,只会在运行时常量池存在一份,这是一种优化。

运行时常量池的作用是存储class文件常量池中的符号引用,同时运行时常量池保存着class文件中描述的符号引用,在类的解析阶段会把这些符号引用转换成直接引用(实例对象的内存地址),翻译出来的直接引用也是存储在运行时常量池中。class文件常量池的大部分数据会被加载到运行时常量池。

运行时常量池相比于class文件常量池具有动态性,运行时常量池的内容不全部来自于class文件常量池,可以通过代码生成的方式加入到里面。如String.intern。

String.intern()的用法

拿String的内容去Stringtable查找,则返回引用。如果不存在就把该对象的引用存在Stringtable中。

字符串常量池

1.字符串创建的两种方式

  • String rumenz1="入门";
  • String rumenz2=new String("小站");

入门在编译期间就已经确定,会进入字符串常量池,但是字符串常量池只会保存一个引用,最终还是会在堆上创建一个入门对象。new String这种方式调用了String类的构造函数,new是创建一个对象实例并初始化该实例,因此这个字符串对象是在运行时才能确定的,创建的实例在堆上。

2.字符串常量的本质

字符串常量池是JVM维护的一个字符串实例引用表,在HotSpot VM中它是叫做一个StringTable的全局表。在字符串常量池中维护的是字符串实例的引用,底层C++维护的就是一个Hashtable。这些被维护引用的字符串实例,被称作被驻留字符串interned string进入字符串常量池的字符串

查看原文

赞 0 收藏 0 评论 0

入门小站 发布了文章 · 10月16日

Java垃圾回收jconsole分析

环境:jdk1.8+Mac+Idea
为了便于观察我们设置了虚拟机的参数VM oprions,-Xms10m -Xmx10m

代码案例1:

新建了一个数组,向里面添加100个OutOfMemory
package com.rumenz;

import java.util.ArrayList;
import java.util.List;

public class OutOfMemory {
    
    public byte []one=new byte[128*1024];
    
    public static void main(String[] args) throws InterruptedException {
            Thread.sleep(5000); //延时5秒,方便我们打开`jconsole`
            append(100);
    }
    private static void append(int n) throws InterruptedException {
        List<OutOfMemory> list=new ArrayList<>();
        for (int i = 0; i < n; i++) {
            Thread.sleep(3000); //拖慢添加速度,方便我们观察
            list.add(new OutOfMemory());
        }

    }
}

运行程序后迅速打开jconsole,并找到自己编写的类,点击进入,选择不安全链接

> jconsole

image-20201016132800820

由于我们使用的是成员变量,所以垃圾回收器一致不能回收内存,所以整个堆的内存趋势是一路上涨.

image-20201016135325459

代码案例2:

package com.rumenz;
import java.util.ArrayList;
import java.util.List;

public class OutOfMemory {


    public OutOfMemory() {
            byte []one=new byte[128*1024];
    }
    public static void main(String[] args) throws InterruptedException {

            Thread.sleep(5000);
            append(100);
    }

    private static void append(int n) throws InterruptedException {
        List<OutOfMemory> list=new ArrayList<>();
        for (int i = 0; i < n; i++) {
            Thread.sleep(3000);
            list.add(new OutOfMemory());
        }

    }
}
与上面代码的区别我们one变量有成员变量变成了局部变量. 局部变量在栈上分配内存,当方法结束,栈空间消失,栈上的变量或者引用地址将失效,本案例中one对象是分配在堆内存上,栈空间的消失导致one对象无法被使用到,随后就会被垃圾回收掉. 所以本案例的堆内存变量将呈现出折线的效果.

image-20201016140148961

查看原文

赞 0 收藏 0 评论 0

入门小站 发布了文章 · 10月14日

Java内存溢出OOM使用Mat分析

示例

package com.rumenz;

import java.util.ArrayList;
import java.util.List;

public class OutOfMemory {

    public static void main(String[] args) {
         List<UserTest> res=new ArrayList<>();
         while (true){
             res.add(new UserTest());
         }
    }
}

class UserTest{

}

VM 添加参数

-Xms20m -Xmx20m

输出:

Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
    at com.rumenz.OutOfMemory.main(OutOfMemory.java:11)

解释:

通过VM参数控制JVM的堆内存大小只有20m,程序不停的创建对象,而对象又是在堆上分配内存,一直不停的向List中添加对象,没有垃圾回收,导致堆内存溢出(OutOfMemoryError).

Mat工具分析堆

1.下载Mat分析软件:https://www.eclipse.org/mat/d...

2.VM参数加上: -XX:+HeapDumpOnOutOfMemoryError开启堆内存溢出导出堆内存到文件,默认在项目的根目录下.如果需要指定其它路径用-XX:HeapDumpPath=/tmp,会生成一个名字类似的java_pid28790.hprof文件.

3.使用Mat打开hprof文件

image-20201014114417693

java.lang.Object[14053]含义:
List<UserTest>本质上就是Object[]数组,14053就是里面存放的对象的个数.

  • Shallow Heap (浅层堆)表示:对象实际占用的堆大小(不包含其它引用对象的大小)
  • Retained Heap(保留堆)表示:对象实际占用+所包含引用对象的大小

Shallow Heap计算方法

在本次案例中:Shallow Heap占用112448字节,Retained Heap占用337296字节.

List<UserTest> res=new ArrayList<>(); res是局部变量,在栈上分配内存,res中存放的是UserTest实例对象的堆内存地址(引用),JDK1.8中打开指针压缩(-XX:+UseCompressedOops),在64位系统引用就占4个字节,未打开指针压缩64位系统中引用指针占用8个字节.

当前案例未打开指针压缩:
14053个引用地址占用内存大小: `14053*8=112424`,`Shallow Heap`占用`112448`字节,还有24字节明显就是res容器本身占用的内存大小.

数组浅堆占用内存计算:

16 bytes of overhead 对象的头
4 bytes length 存储容器长度
4 bytes padding 字节对其

16 bytes of overhead + 4 bytes length + 4 bytes padding = 24 bytes

Retained Heap计算方法

Retained Heap Size=Shallow Heap Size+引用对象实际大小

Shallow Heap 已经计算出来了
引用对象的实际大小:本案例中,由于UserTest是一个空的对象,所以每个UserTest实例对象就只占用16字节的对象头.总共有14053个实例对象,所以共占用14053*17=224848.

Retained Heap=112424+224848=337296和Mat分析的结果一致.

查看原文

赞 0 收藏 0 评论 0

入门小站 发布了文章 · 10月13日

JVM,JRE,JDK之间的区别和联系

jdl, jre, jvm

JDK包含了JRE,JRE包含了JVM
  • JDK:java开发工具包,针对java开发人员,可以编译运行java程序
  • JRE:java运行时环境,针对使用java程序的客户,可以运行字节码(.class),但是不能编译Java源码
  • JVM:用来解释执行字节码文件(.class),但不能正确的执行

什么是JVM

JVM是JRE的一部分,是虚拟出来的一台计算机.通过实体计算机仿真各种计算功能来实现,JVM有自己完善的硬件架构,如处理器,堆栈,寄存器等,还有相应的指令集.JVM是Java跨平台的核心,Java程序通过JVM的跨平台,从而使Java程序跨平台.Java程序首选会被编译成字节码文件(.class),JVM的核心任务就是解释字节码文件(.class)并映射到真实CPU指令集或者系统调用.JVM不关系上层Java程序,只关系字节码(.class).

什么是JRE

JRE是Java运行环境,所有Java程序必须依赖JRE才能运行.只有JVM是不能运行字节码文件的(.class),因为解释的字节码的时候需要lib库. JRE里面有两个文件夹bin/,lib/bin/就是JVM,lib就是JVM所需要库。JVM+lib=JRE

什么是JDK

JDK是Java的核心,包含运行Java运行环境(JRE)和一些Java工具及Java基础类库 。

JDK提供的工具

appletviewer.exe*    java-rmi.exe*  jrunscript.exe*    policytool.exe*
extcheck.exe*        javaw.exe*     jsadebugd.exe*     rmic.exe*
idlj.exe*            javaws.exe*    jstack.exe*        rmid.exe*
jabswitch.exe*       jcmd.exe*      jstat.exe*         rmiregistry.exe*
jar.exe*             jconsole.exe*  jstatd.exe*        schemagen.exe*
jarsigner.exe*       jdb.exe*       jvisualvm.exe*     serialver.exe*
java.exe*            jdeps.exe*     keytool.exe*       servertool.exe*
javac.exe*           jhat.exe*      kinit.exe*         tnameserv.exe*
javadoc.exe*         jinfo.exe*     klist.exe*         unpack200.exe*
javafxpackager.exe*  jjs.exe*       ktab.exe*          vcruntime140.dll*
javah.exe*           jli.dll*       native2ascii.exe*  wsgen.exe*
javap.exe*           jmap.exe*      orbd.exe*          wsimport.exe*
javapackager.exe*    jps.exe*       pack200.exe*       xjc.exe*

Java Api是Java的应用程序接口,里面有很多写好的Java Class,包含一些重要的语法结构以及基本图形,网络和文件IO,我们可以直接调用。

总结

  • 有JVM和lib库(JRE)就可以执行字节码(.class)文件(Java程序)
  • 有JRE可以运行(Java程序)但是还不能开发Java程序,需要JDK(JRE+开发工具)才可以

windows 安装jdk

image-20201013130923240

会发现有两个目录,其实只需要jdk1.8.0_91就可以,里面包好了jre,jre1.8.0_91是JDK单独提供一个一个运行环境

两个目录jre的区别

  • 相同点:这两个JRE都可以作为Java程序的运行环境
  • 不同点:JDK只能使用自己目录自带的JRE,不能使用外面单独安装的JRE

开发到运行

安装JDK环境,调用本地的Java api完成业务代码,通过JDK的编译器(javac)编译成字节码(.class),然后在JRE上运行这些JAVA字节码,JVM解释这些字节码,映射到CPU指令集或者系统调用。

查看原文

赞 0 收藏 0 评论 0

入门小站 发布了文章 · 10月6日

Centos7 安装Oracle JDK1.8和OpenJDK 1.8

首先:Oracle JDKOpenJDK装任何一个就可以了.
Oracle JDK和OpenJDK的区别:

Oracle JDK由Oracle公司开发,该公司是Sun许可证,基于Java标准版规范实现。它以二进制产品的形式发布。它支持多种操作系统,如Windows,Linux,Solaris,MacOS等。它支持不同的平台,如Intel 32位和64位架构,ARM架构和SPARC。它完全基于Java编程语言。之后,该许可证宣布将根据GPL(通用公共许可证)许可证发布。Oracle JDK包含许多组件作为库形式的编程工具集合

OpenJDK是Java SE平台版的开源和免费实现,它是Sun Corporation(现在的Oracle Corporation)于2006年开始的开发结果。它是根据GNU GPL许可证授权的。它最初于2007年发布。它由Oracle Corporation,Red Hat,IBM,Apple Inc.,OpenJDK和Java Community等开发。它是使用C ++和Java编程语言编写的。它支持不同的操作系统,如FreeBSD,Linux,Microsoft Windows,Mac OS X. OpenJDK是Java SE Platform Edition的官方参考实现。

Oracle与OpenJDK之间比较Oracle JDKOpenJDK
执照它是根据GPL(通用公共许可证)许可证授权的它是根据GNU GPL(通用公共许可证)许可证授权的
发展由Sun Microsystems Inc.开发由Oracle,OpenJDK和Java社区开发
性能根据Sun JDK的开发和实现提供性能提供由Oracle JDK之上的一些供应商开发的高性能
可扩展性根据Sun的实施可以使用其他库或Oracle JDK进行改进
费用Sun的官方执行许可证开源和免费实施可供免费使用
速度由Sun Microsystems Inc.开发第三方供应商将通过进行一些调整来提高JVM的速度
操作系统支持Windows,Linux,Solaris,MacOSFreeBSD,Linux,Microsoft Windows,Mac OS X.
便于使用可以与任何应用程序开发一起使用可以与任何应用程序开发和其他开源工具一起使用,以提高开源实现模型的性能。

Oracle JDK1.8的安装

1.下载 jdk-8u261-linux-x64.tar.gz
链接: https://pan.baidu.com/s/1_x5W... 密码: 6pat

2.创建目录

# 把 jdk-8u261-linux-x64.tar.gz通过ftp传送到Centos7服务器
> mkdir /usr/local/java
> tar -xzvf jdk-8u261-linux-x64.tar.gz -C /usr/local/java
> mv /usr/local/java/jdk1.8.0_261 /usr/local/java/jdk1.8

3.配置环境变量


> vi /etc/profile
# 添加JAVA_HOME环境变量到文件末尾
export JAVA_HOME=/usr/local/java/jdk1.8
export PATH=${JAVA_HOME}/bin:${PATH}
> source /etc/profile

4.测试

> java -version

Open JDK1.8的安装

1.查看jdk1.8可用版本

> yum -y list java-1.8*

2.安装Open JDK1.8

> yum install java-1.8* -y

3.查看Open JDK1.8安装路径

> rpm -qa | grep openjdk
java-1.8.0-openjdk-1.8.0.262.b10-0.el7_8.x86_64
java-1.8.0-openjdk-devel-1.8.0.262.b10-0.el7_8.x86_64
java-1.8.0-openjdk-headless-1.8.0.262.b10-0.el7_8.x86_64
java-1.8.0-openjdk-demo-1.8.0.262.b10-0.el7_8.x86_64
java-1.8.0-openjdk-src-1.8.0.262.b10-0.el7_8.x86_64
java-1.8.0-openjdk-javadoc-zip-1.8.0.262.b10-0.el7_8.noarch
java-1.8.0-openjdk-accessibility-1.8.0.262.b10-0.el7_8.x86_64
java-1.8.0-openjdk-javadoc-1.8.0.262.b10-0.el7_8.noarch

> rpm -ql  java-1.8.0-openjdk-1.8.0.262.b10-0.el7_8.x86_64

/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.262.b10-0.el7_8.x86_64/jre/bin/policytool
/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.262.b10-0.el7_8.x86_64/jre/lib/amd64/libawt_xawt.so
/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.262.b10-0.el7_8.x86_64/jre/lib/amd64/libjawt.so
/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.262.b10-0.el7_8.x86_64/jre/lib/amd64/libjsoundalsa.so
/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.262.b10-0.el7_8.x86_64/jre/lib/amd64/libsplashscreen.so
/usr/share/applications/java-1.8.0-openjdk-1.8.0.262.b10-0.el7_8.x86_64-policytool.desktop
/usr/share/icons/hicolor/16x16/apps/java-1.8.0-openjdk.png
/usr/share/icons/hicolor/24x24/apps/java-1.8.0-openjdk.png
/usr/share/icons/hicolor/32x32/apps/java-1.8.0-openjdk.png
/usr/share/icons/hicolor/48x48/apps/java-1.8.0-openjdk.png
/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.262.b10-0.el7_8.x86_64为Open JDK1.8的安装路径

4.配置环境变量

> vi /etc/profile
# 添加JAVA_HOME环境变量到文件末尾
export  JAVA_HOME=/usr/lib/jvm/java-1.8.0-openjdk-1.8.0.262.b10-0.el7_8.x86_64
export  PATH=${JAVA_HOME}/bin:${PATH}

5.测试

> java -version

查看原文

赞 0 收藏 0 评论 0

入门小站 发布了文章 · 10月5日

Pandas入门教程(六)

import pandas as pd
gl=pd.read_csv('./pandas/data/game_logs.csv')
# 数据的内存使用情况
gl.info(memory_usage='deep')
<class 'pandas.core.frame.DataFrame'>
RangeIndex: 171907 entries, 0 to 171906
Columns: 161 entries, date to acquisition_info
dtypes: float64(77), int64(6), object(78)
memory usage: 859.4 MB


for dtype in ['float64','object','int64']:
    selected_dtype=gl.select_dtypes(include=[dtype])
    memory_usage_b=selected_dtype.memory_usage(deep=True).mean()
    memory_usage_mb=memory_usage_b/1024/1024
    print('[%s] memory usage %0.2f MB' % (dtype,memory_usage_mb))
[float64] memory usage 1.29 MB
[object] memory usage 9.50 MB
[int64] memory usage 1.12 MB


# uint8 int8 int16 int32 int64的取值范围
import numpy as np
for dtype in ['uint8','int8','int16','int32','int64']:
    print(np.iinfo(dtype))
Machine parameters for uint8
---------------------------------------------------------------
min = 0
max = 255
---------------------------------------------------------------

Machine parameters for int8
---------------------------------------------------------------
min = -128
max = 127
---------------------------------------------------------------

Machine parameters for int16
---------------------------------------------------------------
min = -32768
max = 32767
---------------------------------------------------------------

Machine parameters for int32
---------------------------------------------------------------
min = -2147483648
max = 2147483647
---------------------------------------------------------------

Machine parameters for int64
---------------------------------------------------------------
min = -9223372036854775808
max = 9223372036854775807
---------------------------------------------------------------



# 类型转换后的数据占用内存
def mem_usage(data):
    if isinstance(data,pd.DataFrame):
        mem_b=data.memory_usage(deep=True).sum()
    else:
        mem_b=data.memory_usage(deep=True)
    return "{:03.2f} MB".format(mem_b/1024**2)

gl_int64=gl.select_dtypes(include=['int64'])

# 向下类型转换
gl_int32=gl_int.apply(pd.to_numeric,downcast='unsigned')
print(mem_usage(gl_int64))
print(mem_usage(gl_int32))

# float64 转 float
gl_float64=gl.select_dtypes(include=['float64'])
gl_float=gl_float64.apply(pd.to_numeric,downcast='float')

print("转换前:"+mem_usage(gl_float64))
print("转换后"+mem_usage(gl_float))
7.87 MB
1.48 MB
转换前:100.99 MB
转换后50.49 MB


opt_gl=gl.copy()
opt_gl[gl_int32.columns]=gl_int32
opt_gl[gl_float.columns]=gl_float
print("原数据的大小:"+mem_usage(gl))
print("转换后的数据大小:"+mem_usage(opt_gl))
原数据的大小:859.43 MB
转换后的数据大小:802.54 MB


gl_obj=gl.select_dtypes(include=['object']).copy()
print(gl_obj.describe())
       day_of_week  v_name v_league  h_name h_league day_night  \
count       171907  171907   171907  171907   171907    140150   
unique           7     148        7     148        7         2   
top            Sat     CHN       NL     CHN       NL         D   
freq         28891    8870    88866    9024    88867     82724   

                   completion forefeit protest park_id  ... h_player_6_id  \
count                     116      145     180  171907  ...        140838   
unique                    116        3       5     245  ...          4774   
top     19590602,PIT06,2,1,39        H       V   STL07  ...      grimc101   
freq                        1       69      90    7022  ...           427   

       h_player_6_name h_player_7_id h_player_7_name h_player_8_id  \
count           140838        140838          140838        140838   
unique            4720          5253            5197          4760   
top      Charlie Grimm      grimc101   Charlie Grimm      lopea102   
freq               427           491             491           676   

       h_player_8_name h_player_9_id h_player_9_name additional_info  \
count           140838        140838          140838            1456   
unique            4710          5193            5142             332   
top           Al Lopez      spahw101    Warren Spahn            HTBF   
freq               676           339             339            1112   

       acquisition_info  
count            140841  
unique                1  
top                   Y  
freq             140841  

[4 rows x 78 columns]


dow=gl_obj.day_of_week
print(dow.head())
dow_cat=dow.astype('category')
print(dow_cat.head())
print("转换前"+mem_usage(dow))
print("转换后"+mem_usage(dow_cat))
# 将重复比较多的数据转换成category,缩小数据内存
convert_obj=pd.DataFrame()
for col in gl_obj.columns:
    num_unique=len(gl_obj[col].unique())
    num_total=len(gl_obj[col])
    if num_unique/num_total<0.5:
        convert_obj.loc[:,col]=gl_obj[col].astype('category')
    else:
        convert_obj.loc[:,col]=gl_obj[col]

print('数据转换前:'+mem_usage(gl_obj))
print('数据转换后:'+mem_usage(convert_obj))
opt_gl[convert_obj.columns]=convert_obj
print(mem_usage(opt_gl))
# apply操作
titanic=pd.read_csv('./pandas/data/titanic_train.csv')
titanic.iloc[99]
# 获取99行的数据
def get_row(data):
    return data.iloc[99]
row=titanic.apply(get_row)
row
# 统计每一列为NaN的数量
def get_null_count(data):
    col_null=pd.isnull(data)
    null=data[col_null]
    return len(null)
null_count=titanic.apply(get_null_count)
print(null_count)
# 数据转换
def which_class(row):
    pclass=row['Pclass']
    if pd.isnull(pclass):
        return "UnKown"
    elif pclass == 1:
        return "One"
    elif pclass == 2:
        return "Tow"
    elif pclass == 3:
        return "Three"
classes=titanic.apply(which_class,axis=1)
print(classes)
# 找出未成年的数据
def is_minor(row):
    age=row['Age']
    if age<18:
        return True
    else:
        return False

minor=titanic.apply(is_minor,axis=1)
print(titanic[minor])

查看原文

赞 0 收藏 0 评论 0

认证与成就

  • 获得 7 次点赞
  • 获得 1 枚徽章 获得 0 枚金徽章, 获得 0 枚银徽章, 获得 1 枚铜徽章

擅长技能
编辑

(゚∀゚ )
暂时没有

开源项目 & 著作
编辑

(゚∀゚ )
暂时没有

注册于 2018-07-05
个人主页被 419 人浏览