百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术资源 > 正文

JVM性能调优常用命令 jvm性能调优实战

lipiwang 2024-10-23 13:57 15 浏览 0 评论

jmap

jmap 即 JVM Memory Map。

jmap 用于生成 heap dump 文件。

如果不使用这个命令,还可以使用 -XX:+HeapDumpOnOutOfMemoryError 参数来让虚拟机出现 OOM 的时候,自动生成 dump 文件。

jmap 不仅能生成 dump 文件,还可以查询 finalize 执行队列、Java 堆和永久代的详细信息,如当前使用率、当前使用的是哪种收集器等。

命令格式:

jmap [option] LVMID

option 参数:

  • dump - 生成堆转储快照
  • finalizerinfo - 显示在 F-Queue 队列等待 Finalizer 线程执行 finalizer 方法的对象
  • heap - 显示 Java 堆详细信息
  • histo - 显示堆中对象的统计信息
  • permstat - to print permanent generation statistics
  • F - 当-dump 没有响应时,强制生成 dump 快照

示例:jmap -dump PID 生成堆快照

dump 堆到文件,format 指定输出格式,live 指明是活着的对象,file 指定文件名

$ jmap -dump:live,format=b,file=dump.hprof 28920
Dumping heap to /home/xxx/dump.hprof ...
Heap dump file created

dump.hprof 这个后缀是为了后续可以直接用 MAT(Memory Anlysis Tool)打开。

示例:jmap -heap 查看指定进程的堆信息

注意:使用 CMS GC 情况下,jmap -heap 的执行有可能会导致 java 进程挂起。

jmap -heap PID
[root@chances bin]# ./jmap -heap 12379
Attaching to process ID 12379, please wait...
Debugger attached successfully.
Server compiler detected.
JVM version is 17.0-b16

using thread-local object allocation.
Parallel GC with 6 thread(s)

Heap Configuration:
   MinHeapFreeRatio = 40
   MaxHeapFreeRatio = 70
   MaxHeapSize      = 83886080 (80.0MB)
   NewSize          = 1310720 (1.25MB)
   MaxNewSize       = 17592186044415 MB
   OldSize          = 5439488 (5.1875MB)
   NewRatio         = 2
   SurvivorRatio    = 8
   PermSize         = 20971520 (20.0MB)
   MaxPermSize      = 88080384 (84.0MB)

Heap Usage:
PS Young Generation
Eden Space:
   capacity = 9306112 (8.875MB)
   used     = 5375360 (5.1263427734375MB)
   free     = 3930752 (3.7486572265625MB)
   57.761608714788736% used
From Space:
   capacity = 9306112 (8.875MB)
   used     = 3425240 (3.2665634155273438MB)
   free     = 5880872 (5.608436584472656MB)
   36.80634834397007% used
To Space:
   capacity = 9306112 (8.875MB)
   used     = 0 (0.0MB)
   free     = 9306112 (8.875MB)
   0.0% used
PS Old Generation
   capacity = 55967744 (53.375MB)
   used     = 48354640 (46.11457824707031MB)
   free     = 7613104 (7.2604217529296875MB)
   86.39733629427693% used
PS Perm Generation
   capacity = 62062592 (59.1875MB)
   used     = 60243112 (57.452308654785156MB)
   free     = 1819480 (1.7351913452148438MB)
   97.06831451706046% used

jstack

jstack 用于生成 java 虚拟机当前时刻的线程快照。

线程快照是当前 java 虚拟机内每一条线程正在执行的方法堆栈的集合,生成线程快照的主要目的是定位线程出现长时间停顿的原因,如线程间死锁、死循环、请求外部资源导致的长时间等待等。

线程出现停顿的时候通过 jstack 来查看各个线程的调用堆栈,就可以知道没有响应的线程到底在后台做什么事情,或者等待什么资源。 如果 java 程序崩溃生成 core 文件,jstack 工具可以用来获得 core 文件的 java stack 和 native stack 的信息,从而可以轻松地知道 java 程序是如何崩溃和在程序何处发生问题。另外,jstack 工具还可以附属到正在运行的 java 程序中,看到当时运行的 java 程序的 java stack 和 native stack 的信息, 如果现在运行的 java 程序呈现 hung 的状态,jstack 是非常有用的。

命令格式:

jstack [option] LVMID

option 参数:

  • -F - 当正常输出请求不被响应时,强制输出线程堆栈
  • -l - 除堆栈外,显示关于锁的附加信息
  • -m - 如果调用到本地方法的话,可以显示 C/C++的堆栈

jps

jps(JVM Process Status Tool),显示指定系统内所有的 HotSpot 虚拟机进程。

命令格式:

jps [options] [hostid]

option 参数:

  • -l - 输出主类全名或 jar 路径
  • -q - 只输出 LVMID
  • -m - 输出 JVM 启动时传递给 main()的参数
  • -v - 输出 JVM 启动时显示指定的 JVM 参数

其中[option]、[hostid]参数也可以不写。

$ jps -l -m
28920 org.apache.catalina.startup.Bootstrap start
11589 org.apache.catalina.startup.Bootstrap start
25816 sun.tools.jps.Jps -l -m

jstat

jstat(JVM statistics Monitoring),是用于监视虚拟机运行时状态信息的命令,它可以显示出虚拟机进程中的类装载、内存、垃圾收集、JIT 编译等运行数据。

命令格式:

jstat [option] LVMID [interval] [count]

参数:

  • [option] - 操作参数
  • LVMID - 本地虚拟机进程 ID
  • [interval] - 连续输出的时间间隔
  • [count] - 连续输出的次数

jhat

jhat(JVM Heap Analysis Tool),是与 jmap 搭配使用,用来分析 jmap 生成的 dump,jhat 内置了一个微型的 HTTP/HTML 服务器,生成 dump 的分析结果后,可以在浏览器中查看。

注意:一般不会直接在服务器上进行分析,因为 jhat 是一个耗时并且耗费硬件资源的过程,一般把服务器生成的 dump 文件复制到本地或其他机器上进行分析。

命令格式:

jhat [dumpfile]

jinfo

jinfo(JVM Configuration info),用于实时查看和调整虚拟机运行参数。

之前的 jps -v 口令只能查看到显示指定的参数,如果想要查看未被显示指定的参数的值就要使用 jinfo 口令

命令格式:

jinfo [option] [args] LVMID

option 参数:

-flag : 输出指定 args 参数的值-flags : 不需要 args 参数,输出所有 JVM 参数的值-sysprops : 输出系统属性,等同于 System.getProperties()

HotSpot VM 参数

详细参数说明请参考官方文档:Java HotSpot VM Options,这里仅列举常用参数。

JVM 内存配置

配置描述-Xms堆空间初始值。-Xmx堆空间最大值。-XX:NewSize新生代空间初始值。-XX:MaxNewSize新生代空间最大值。-Xmn新生代空间大小。-XX:PermSize永久代空间的初始值。-XX:MaxPermSize永久代空间的最大值。

GC 类型配置

配置描述-XX:+UseSerialGC串行垃圾回收器-XX:+UseParallelGC并行垃圾回收器-XX:+UseParNewGC使用 ParNew + Serial Old 垃圾回收器组合-XX:+UseConcMarkSweepGC并发标记扫描垃圾回收器-XX:ParallelCMSThreads=并发标记扫描垃圾回收器 = 为使用的线程数量-XX:+UseG1GCG1 垃圾回收器

辅助配置

配置描述-XX:+PrintGCDetails打印 GC 日志-Xloggc:<filename>指定 GC 日志文件名-XX:+HeapDumpOnOutOfMemoryError内存溢出时输出堆快照文件

典型配置

堆大小设置

年轻代的设置很关键。

JVM 中最大堆大小有三方面限制:

  1. 相关操作系统的数据模型(32-bt 还是 64-bit)限制;
  2. 系统的可用虚拟内存限制;
  3. 系统的可用物理内存限制。
整个堆大小 = 年轻代大小 + 年老代大小 + 持久代大小
  • 持久代一般固定大小为 64m。使用 -XX:PermSize 设置。
  • 官方推荐年轻代占整个堆的 3/8。使用 -Xmn 设置。

回收器选择

JVM 给了三种选择:串行收集器、并行收集器、并发收集器。

JVM 实战

分析 GC 日志

获取 GC 日志

获取 GC 日志有两种方式:

  • 使用命令动态查看
  • 在容器中设置相关参数打印 GC 日志

jstat -gc 统计垃圾回收堆的行为:

jstat -gc 1262
 S0C    S1C     S0U     S1U   EC       EU        OC         OU        PC       PU         YGC    YGCT    FGC    FGCT     GCT
26112.0 24064.0 6562.5  0.0   564224.0 76274.5   434176.0   388518.3  524288.0 42724.7    320    6.417   1      0.398    6.815

也可以设置间隔固定时间来打印:

$ jstat -gc 1262 2000 20

这个命令意思就是每隔 2000ms 输出 1262 的 gc 情况,一共输出 20 次

Tomcat 设置示例:

JAVA_OPTS="-server -Xms2000m -Xmx2000m -Xmn800m -XX:PermSize=64m -XX:MaxPermSize=256m -XX:SurvivorRatio=4
-verbose:gc -Xloggc:$CATALINA_HOME/logs/gc.log
-Djava.awt.headless=true
-XX:+PrintGCTimeStamps -XX:+PrintGCDetails
-Dsun.rmi.dgc.server.gcInterval=600000 -Dsun.rmi.dgc.client.gcInterval=600000
-XX:+UseConcMarkSweepGC -XX:MaxTenuringThreshold=15"
  • -Xms2000m -Xmx2000m -Xmn800m -XX:PermSize=64m -XX:MaxPermSize=256m Xms,即为 jvm 启动时得 JVM 初始堆大小,Xmx 为 jvm 的最大堆大小,xmn 为新生代的大小,permsize 为永久代的初始大小,MaxPermSize 为永久代的最大空间。
  • -XX:SurvivorRatio=4 SurvivorRatio 为新生代空间中的 Eden 区和救助空间 Survivor 区的大小比值,默认是 8,则两个 Survivor 区与一个 Eden 区的比值为 2:8,一个 Survivor 区占整个年轻代的 1/10。调小这个参数将增大 survivor 区,让对象尽量在 survitor 区呆长一点,减少进入年老代的对象。去掉救助空间的想法是让大部分不能马上回收的数据尽快进入年老代,加快年老代的回收频率,减少年老代暴涨的可能性,这个是通过将-XX:SurvivorRatio 设置成比较大的值(比如 65536)来做到。
  • -verbose:gc -Xloggc:$CATALINA_HOME/logs/gc.log 将虚拟机每次垃圾回收的信息写到日志文件中,文件名由 file 指定,文件格式是平文件,内容和-verbose:gc 输出内容相同。
  • -Djava.awt.headless=true Headless 模式是系统的一种配置模式。在该模式下,系统缺少了显示设备、键盘或鼠标。
  • -XX:+PrintGCTimeStamps -XX:+PrintGCDetails 设置 gc 日志的格式
  • -Dsun.rmi.dgc.server.gcInterval=600000 -Dsun.rmi.dgc.client.gcInterval=600000 指定 rmi 调用时 gc 的时间间隔
  • -XX:+UseConcMarkSweepGC -XX:MaxTenuringThreshold=15 采用并发 gc 方式,经过 15 次 minor gc 后进入年老代

如何分析 GC 日志

Young GC 回收日志:

2016-07-05T10:43:18.093+0800: 25.395: [GC [PSYoungGen: 274931K->10738K(274944K)] 371093K->147186K(450048K), 0.0668480 secs] [Times: user=0.17 sys=0.08, real=0.07 secs]

Full GC 回收日志:

2016-07-05T10:43:18.160+0800: 25.462: [Full GC [PSYoungGen: 10738K->0K(274944K)] [ParOldGen: 136447K->140379K(302592K)] 147186K->140379K(577536K) [PSPermGen: 85411K->85376K(171008K)], 0.6763541 secs] [Times: user=1.75 sys=0.02, real=0.68 secs]

通过上面日志分析得出,PSYoungGen、ParOldGen、PSPermGen 属于 Parallel 收集器。其中 PSYoungGen 表示 gc 回收前后年轻代的内存变化;ParOldGen 表示 gc 回收前后老年代的内存变化;PSPermGen 表示 gc 回收前后永久区的内存变化。young gc 主要是针对年轻代进行内存回收比较频繁,耗时短;full gc 会对整个堆内存进行回城,耗时长,因此一般尽量减少 full gc 的次数

通过两张图非常明显看出 gc 日志构成:

OutOfMemory(OOM)分析

OutOfMemory ,即内存溢出,是一个常见的 JVM 问题。那么分析 OOM 的思路是什么呢?

首先,要知道有三种 OutOfMemoryError:

  • OutOfMemoryError:Java heap space - 堆空间溢出
  • OutOfMemoryError:PermGen space - 方法区和运行时常量池溢出
  • OutOfMemoryError:unable to create new native thread - 线程过多

OutOfMemoryError:PermGen space

OutOfMemoryError:PermGen space 表示方法区和运行时常量池溢出。

原因:

Perm 区主要用于存放 Class 和 Meta 信息的,Class 在被 Loader 时就会被放到 PermGen space,这个区域称为年老代。GC 在主程序运行期间不会对年老区进行清理,默认是 64M 大小。

当程序程序中使用了大量的 jar 或 class,使 java 虚拟机装载类的空间不够,超过 64M 就会报这部分内存溢出了,需要加大内存分配,一般 128m 足够。

解决方案:

(1)扩大永久代空间

  • JDK7 以前使用 -XX:PermSize 和 -XX:MaxPermSize 来控制永久代大小。
  • JDK8 以后把原本放在永久代的字符串常量池移出, 放在 Java 堆中(元空间 Metaspace)中,元数据并不在虚拟机中,使用的是本地的内存。使用 -XX:MetaspaceSize 和 -XX:MaxMetaspaceSize 控制元空间大小。

注意:-XX:PermSize 一般设为 64M

(2)清理应用程序中 WEB-INF/lib 下的 jar,用不上的 jar 删除掉,多个应用公共的 jar 移动到 Tomcat 的 lib 目录,减少重复加载。

OutOfMemoryError:Java heap space

OutOfMemoryError:Java heap space 表示堆空间溢出。

原因:JVM 分配给堆内存的空间已经用满了。

问题定位

(1)使用 jmap 或 -XX:+HeapDumpOnOutOfMemoryError 获取堆快照。 (2)使用内存分析工具(visualvm、mat、jProfile 等)对堆快照文件进行分析。 (3)根据分析图,重点是确认内存中的对象是否是必要的,分清究竟是是内存泄漏(Memory Leak)还是内存溢出(Memory Overflow)。

内存泄露

内存泄漏是指由于疏忽或错误造成程序未能释放已经不再使用的内存的情况。

内存泄漏并非指内存在物理上的消失,而是应用程序分配某段内存后,由于设计错误,失去了对该段内存的控制,因而造成了内存的浪费。

内存泄漏随着被执行的次数越多-最终会导致内存溢出。

而因程序死循环导致的不断创建对象-只要被执行到就会产生内存溢出。

内存泄漏常见几个情况:

  • 静态集合类声明为静态(static)的 HashMap、Vector 等集合通俗来讲 A 中有 B,当前只把 B 设置为空,A 没有设置为空,回收时 B 无法回收-因被 A 引用。
  • 监听器监听器被注册后释放对象时没有删除监听器
  • 物理连接DataSource.getConnection()建立链接,必须通过 close()关闭链接
  • 内部类和外部模块等的引用发现它的方式同内存溢出,可再加个实时观察jstat -gcutil 7362 2500 70

重点关注:

  • FGC — 从应用程序启动到采样时发生 Full GC 的次数。
  • FGCT — 从应用程序启动到采样时 Full GC 所用的时间(单位秒)。
  • FGC 次数越多,FGCT 所需时间越多-可非常有可能存在内存泄漏。

解决方案

(1)检查程序,看是否有死循环或不必要地重复创建大量对象。有则改之。

下面是一个重复创建内存的示例:

public class OOM {
    public static void main(String[] args) {
        Integer sum1=300000;
        Integer sum2=400000;
        OOM oom = new OOM();
        System.out.println("往ArrayList中加入30w内容");
        oom.javaHeapSpace(sum1);
        oom.memoryTotal();
        System.out.println("往ArrayList中加入40w内容");
        oom.javaHeapSpace(sum2);
        oom.memoryTotal();
    }
    public void javaHeapSpace(Integer sum){
        Random random = new Random();  
        ArrayList openList = new ArrayList();
        for(int i=0;i<sum;i++){
            String charOrNum = String.valueOf(random.nextInt(10));
            openList.add(charOrNum);
        }  
    }
    public void memoryTotal(){
        Runtime run = Runtime.getRuntime();
        long max = run.maxMemory();
        long total = run.totalMemory();
        long free = run.freeMemory();
        long usable = max - total + free;
        System.out.println("最大内存 = " + max);
        System.out.println("已分配内存 = " + total);
        System.out.println("已分配内存中的剩余空间 = " + free);
        System.out.println("最大可用内存 = " + usable);
    }
}

执行结果:

往ArrayList中加入30w内容
最大内存 = 20447232
已分配内存 = 20447232
已分配内存中的剩余空间 = 4032576
最大可用内存 = 4032576
往ArrayList中加入40w内容
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
    at java.util.Arrays.copyOf(Arrays.java:2245)
    at java.util.Arrays.copyOf(Arrays.java:2219)
    at java.util.ArrayList.grow(ArrayList.java:242)
    at java.util.ArrayList.ensureExplicitCapacity(ArrayList.java:216)
    at java.util.ArrayList.ensureCapacityInternal(ArrayList.java:208)
    at java.util.ArrayList.add(ArrayList.java:440)
    at pers.qingqian.study.seven.OOM.javaHeapSpace(OOM.java:36)
    at pers.qingqian.study.seven.OOM.main(OOM.java:26)

(2)扩大堆内存空间

使用 -Xms 和 -Xmx 来控制堆内存空间大小。

OutOfMemoryError: GC overhead limit exceeded

原因:JDK6 新增错误类型,当 GC 为释放很小空间占用大量时间时抛出;一般是因为堆太小,导致异常的原因,没有足够的内存。

解决方案:

查看系统是否有使用大内存的代码或死循环; 通过添加 JVM 配置,来限制使用内存:

<jvm-arg>-XX:-UseGCOverheadLimit</jvm-arg>

OutOfMemoryError:unable to create new native thread

原因:线程过多

那么能创建多少线程呢?这里有一个公式:

(MaxProcessMemory - JVMMemory - ReservedOsMemory) / (ThreadStackSize) = Number of threads  
MaxProcessMemory 指的是一个进程的最大内存  
JVMMemory         JVM内存  
ReservedOsMemory  保留的操作系统内存  
ThreadStackSize      线程栈的大小

当发起一个线程的创建时,虚拟机会在 JVM 内存创建一个 Thread 对象同时创建一个操作系统线程,而这个系统线程的内存用的不是 JVMMemory,而是系统中剩下的内存: (MaxProcessMemory - JVMMemory - ReservedOsMemory) 结论:你给 JVM 内存越多,那么你能用来创建的系统线程的内存就会越少,越容易发生 java.lang.OutOfMemoryError: unable to create new native thread。

CPU 过高

定位步骤:

(1)执行 top -c 命令,找到 cpu 最高的进程的 id

(2)jstack PID 导出 Java 应用程序的线程堆栈信息。

示例:

jstack 6795

"Low Memory Detector" daemon prio=10 tid=0x081465f8 nid=0x7 runnable [0x00000000..0x00000000]  
        "CompilerThread0" daemon prio=10 tid=0x08143c58 nid=0x6 waiting on condition [0x00000000..0xfb5fd798]  
        "Signal Dispatcher" daemon prio=10 tid=0x08142f08 nid=0x5 waiting on condition [0x00000000..0x00000000]  
        "Finalizer" daemon prio=10 tid=0x08137ca0 nid=0x4 in Object.wait() [0xfbeed000..0xfbeeddb8]  

        at java.lang.Object.wait(Native Method)  

        - waiting on <0xef600848> (a java.lang.ref.ReferenceQueue$Lock)  

        at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:116)  

        - locked <0xef600848> (a java.lang.ref.ReferenceQueue$Lock)  

        at java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:132)  

        at java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:159)  

        "Reference Handler" daemon prio=10 tid=0x081370f0 nid=0x3 in Object.wait() [0xfbf4a000..0xfbf4aa38]  

        at java.lang.Object.wait(Native Method)  

        - waiting on <0xef600758> (a java.lang.ref.Reference$Lock)  

        at java.lang.Object.wait(Object.java:474)  

        at java.lang.ref.Reference$ReferenceHandler.run(Reference.java:116)  

        - locked <0xef600758> (a java.lang.ref.Reference$Lock)  

        "VM Thread" prio=10 tid=0x08134878 nid=0x2 runnable  

        "VM Periodic Task Thread" prio=10 tid=0x08147768 nid=0x8 waiting on condition

在打印的堆栈日志文件中,tid 和 nid 的含义:

nid : 对应的 Linux 操作系统下的 tid 线程号,也就是前面转化的 16 进制数字
tid: 这个应该是 jvm 的 jmm 内存规范中的唯一地址定位

在 CPU 过高的情况下,查找响应的线程,一般定位都是用 nid 来定位的。而如果发生死锁之类的问题,一般用 tid 来定位。

(3)定位 CPU 高的线程打印其 nid

查看线程下具体进程信息的命令如下:

top -H -p 6735

相关推荐

前端入门——css 网格轨道详细介绍

上篇前端入门——cssGrid网格基础知识整体大概介绍了cssgrid的基本概念及使用方法,本文将介绍创建网格容器时会发生什么?以及在网格容器上使用行、列属性如何定位元素。在本文中,将介绍:...

Islands Architecture(孤岛架构)在携程新版首页的实践

一、项目背景2022,携程PC版首页终于迎来了首次改版,完成了用户体验与技术栈的全面升级。作为与用户连接的重要入口,旧版PC首页已经陪伴携程走过了22年,承担着重要使命的同时,也遇到了很多问题:维护/...

HTML中script标签中的那些属性

HTML中的<script>标签详解在HTML中,<script>标签用于包含或引用JavaScript代码,是前端开发中不可或缺的一部分。通过合理使用<scrip...

CSS 中各种居中你真的玩明白了么

页面布局中最常见的需求就是元素或者文字居中了,但是根据场景的不同,居中也有简单到复杂各种不同的实现方式,本篇就带大家一起了解下,各种场景下,该如何使用CSS实现居中前言页面布局中最常见的需求就是元...

CSS样式更改——列表、表格和轮廓

上篇文章主要介绍了CSS样式更改篇中的字体设置Font&边框Border设置,这篇文章分享列表、表格和轮廓,一起来看看吧。1.列表List1).列表的类型<ulstyle='list-...

一文吃透 CSS Flex 布局

原文链接:一文吃透CSSFlex布局教学游戏这里有两个小游戏,可用来练习flex布局。塔防游戏送小青蛙回家Flexbox概述Flexbox布局也叫Flex布局,弹性盒子布局。它决定了...

css实现多行文本的展开收起

背景在我们写需求时可能会遇到类似于这样的多行文本展开与收起的场景:那么,如何通过纯css实现这样的效果呢?实现的难点(1)位于多行文本右下角的展开收起按钮。(2)展开和收起两种状态的切换。(3)文本...

css 垂直居中的几种实现方式

前言设计是带有主观色彩的,同样网页设计中的css一样让人摸不头脑。网上列举的实现方式一大把,或许在这里你都看到过,但既然来到这里我希望这篇能让你看有所收获,毕竟这也是前端面试的基础。实现方式备注:...

WordPress固定链接设置

WordPress设置里的最后一项就是固定链接设置,固定链接设置是决定WordPress文章及静态页面URL的重要步骤,从站点的SEO角度来讲也是。固定链接设置决定网站URL,当页面数少的时候,可以一...

面试发愁!吃透 20 道 CSS 核心题,大厂 Offer 轻松拿

前端小伙伴们,是不是一想到面试里的CSS布局题就发愁?写代码时布局总是对不齐,面试官追问兼容性就卡壳,想跳槽却总被“多列等高”“响应式布局”这些问题难住——别担心!从今天起,咱们每天拆解一...

3种CSS清除浮动的方法

今天这篇文章给大家介绍3种CSS清除浮动的方法。有一定的参考价值,有需要的朋友可以参考一下,希望对大家有所帮助。首先,这里就不讲为什么我们要清楚浮动,反正不清除浮动事多多。下面我就讲3种常用清除浮动的...

2025 年 CSS 终于要支持强大的自定义函数了?

大家好,很高兴又见面了,我是"高级前端进阶",由我带着大家一起关注前端前沿、深入前端底层技术,大家一起进步,也欢迎大家关注、点赞、收藏、转发!1.什么是CSS自定义属性CSS自...

css3属性(transform)的一个css3动画小应用

闲言碎语不多讲,咱们说说css3的transform属性:先上效果:效果说明:当鼠标移到a标签的时候,从右上角滑出二维码。实现方法:HTML代码如下:需要说明的一点是,a链接的跳转需要用javasc...

CSS基础知识(七)CSS背景

一、CSS背景属性1.背景颜色(background-color)属性值:transparent(透明的)或color(颜色)2.背景图片(background-image)属性值:none(没有)...

CSS 水平居中方式二

<divid="parent"><!--定义子级元素--><divid="child">居中布局</div>...

取消回复欢迎 发表评论: