首页 文章 精选 留言 我的

精选列表

搜索[学习],共10000篇文章
优秀的个人博客,低调大师

Jenkins +Gradle实现Android自动化构建(学习笔记三十二)

https://blog.csdn.net/mabeijianxi/article/details/52680283 http://www.liuling123.com/2016/10/jenkins-gradle-auto-build.html Jenkins简介 Jenkins是一个开源软件项目,旨在提供一个开放易用的软件平台,使软件的持续集成变成可能。目前大部分公司都在使用Jenkins来持续构建。 Jenkins下载与安装配置 Jenkins下载 安装Jenkins有两种方式: 第一种就是下载安装包直接安装,下载地址:http://mirrors.jenkins-ci.org 第二种就是下载war包,放到Tomcat中启动。war包下载地址:http://mirrors.jenkins-ci.org/war/, 或者http://updates.jenkins-ci.org/download/war/ 这里因为我电脑上面之前装了Tomcat,所以我使用直接下载war包的方式进行安装。 Jenkins安装 将下载的jenkins.war放到Tomcat下的webapps目录下,然后启动Tomcat。在浏览器中访问”Tomcat访问地址/jenkins”即可安装,因为我的Tomcat装在本机,并且端口为8080,所以访问http://localhost:8080/jenkins/即可进行安装。 Jenkins配置 Jenkins安装之后可以进行用户的权限设置、插件的安装等配置。 用户权限设置 系统管理–>Configure Global Security 如下图所示,在此处可以添加、删除用户以及配置用户权限。 插件安装 搭建Android自动化打包环境需要安装Gradle插件,如果使用Git还需要Git的插件,安装Jenkins时默认已经安装了这两个插件。如果没有安装可以进入“系统管理>管理插件”进行插件的安装。 创建Jenkins任务 要想Jenkins能够帮我们自动构建项目,我们需要创建一个任务,并且配置这个任务要它帮我们执行什么操作,以及什么时候执行等。 如上图所示,点击“新建”按钮并且选择“构建一个自由风格的软件项目”,完了之后会进入到任务的配置界面,配置好之后任务会出现在如上图右边的任务列表中。 任务配置 创建一个任务之后,会自动跳转到任务的配置界面对该任务进行配置,大概包括如下配置: 源码管理 构建项目,当然得有代码了。Jenkins支持使用版本控制工具来进行源码管理,比如Git或者SVN。这里我使用的是Git,项目使用的是我的github上面的一个多渠道打包的demo。在Repository URL中输入项目地址,点击Add按钮添加认证信息,然后选择构建的分支,我这里使用的是master分支。 构建触发器 Jenkins支持上图所示的触发时机配置,如果都不选,则为手动构建,需要点击“立即构建”按钮才构建。 Build periodically:周期进行项目构建(它不关心源码是否发生变化); Build when a change is pushed to GItHub:表示只要GitHub上面源码一更新即进行构件; Poll SCM:定时检查源码变更(根据SCM软件的版本号),如果有更新就checkout最新code下来,然后执行构建动作。 Build periodically和Poll SCM都支持日程表的设置,这个与Spring框架中定时器的日程表配置类似,有5个参数: 第一个参数代表的是分钟 minute,取值 0~59; 第二个参数代表的是小时 hour,取值 0~23; 第三个参数代表的是天 day,取值 1~31; 第四个参数代表的是月 month,取值 1~12; 最后一个参数代表的是星期 week,取值 0~7,0 和 7 都是表示星期天。 如: 选择Build periodically并设置日程表为“0 4”,则表示每天凌晨4点构建一次源码。 选择Poll SCM并设置日程表为“ /10”,则表示每10分钟检查一次源码变化,如果有更新才进行构建。 构建工具 因为现在Android项目默认都是使用Gradle来进行构建的,所以在构建中我选择的是Invoke Gradle script。当然你也可以选择其它的构建工具,比如Ant。 选择Invoke Gradle script之后可以选Invoke Gradle和Use Gradle Wrapper,选择Invoke Gradle就是调用本地安装配置好的Gradle,此时需要指定Gradle路径。为了方便所有开发者同意Gradle版本,一般都使用Gradle Wrapper。关于Gradle和Gradlew的区别可以看这篇文章https://www.zybuluo.com/xtccc/note/275168。 Tasks中填上需要执行的gradle的task。上面我填的clean assembleRelease,即执行gradlew clean assembleRelease。 构建后的操作 配置构建后的操作可以让Jenkins在构建完之后执行什么操作,比如邮件通知、构建其它项目等。 这里我配置了Archive the artifacts,在“用于存档的文件”中填写需要存档的文件名,可以使用通配符。比如上面我配置了app/build/outputs/apk/v*.apk,表示疑v开头的apk文件都存档。构建完之后在任务首页可以下载存档的文件。 任务配置完成之后,点击任务首页的“立即构建”按钮,即可开始构建,构建过程首先会将源码下载下来,位于jenkins目录下的workspace中。然后执行配置好的gradle命令,如果使用gradlew,第一次应该会下载gradlew设置的版本的gradle,最后执行构建任务。构建完之后,如下图,可以看到存档的文件,点击即可下载。 附:Android工程build.gradle文件 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 apply plugin:'com.android.application' android { compileSdkVersion23 buildToolsVersion"23.0.2" defaultConfig { applicationId"com.lauren.multichanneldemo" minSdkVersion17 targetSdkVersion23 versionCode1 versionName"1.0" } signingConfigs { release { defliulingStoreFile = System.getenv("LIULING_STORE_FILE") defliulingKeyAlias = System.getenv("LIULING_KEY_ALIAS") defliulingKeyPassword = System.getenv("LIULING_KEY_PASSWORD") defliulingStorePassword = System.getenv("LIULING_STORE_PASSWORD") defisSigning = (liulingStoreFile !=null) && (liulingKeyAlias !=null) && (liulingKeyPassword !=null) && (liulingStorePassword !=null) if(isSigning){ storeFilefile(liulingStoreFile) keyAlias liulingKeyAlias keyPassword liulingKeyPassword storePassword liulingStorePassword }else{ storeFilefile("debug.keystore") keyAlias"AndroidDebugKey" keyPassword"android" storePassword"android" } } debug { storeFilefile("debug.keystore") keyAlias"AndroidDebugKey" keyPassword"android" storePassword"android" } } buildTypes { release { // 不显示Log buildConfigField"boolean","LOG_DEBUG","false" //启用混淆代码的功能 minifyEnabledtrue //压缩对齐生成的apk包 zipAlignEnabledtrue //指定混淆规则,需要压缩优化的混淆要把proguard-android.txt换成proguard-android.txt proguardFiles getDefaultProguardFile('proguard-android.txt'),'proguard-rules.pro' shrinkResourcestrue signingConfig signingConfigs.release//打包命令行:gradlew assembleRelease } debug { signingConfig signingConfigs.debug } } lintOptions { abortOnErrorfalse } // productFlavors { // _91 { // manifestPlaceholders = [MTA_CHANNEL_VALUE: "91"] // } // wandoujia { // manifestPlaceholders = [MTA_CHANNEL_VALUE: "wandoujia"] // } // xiaomi { // manifestPlaceholders = [MTA_CHANNEL_VALUE: "xiaomi"] // } // // _360shoufa{ // manifestPlaceholders = [MTA_CHANNEL_VALUE: "360shoufa"] // } // anzhi{ // manifestPlaceholders = [MTA_CHANNEL_VALUE: "anzhi"] // } // baidushoufa{ // manifestPlaceholders = [MTA_CHANNEL_VALUE: "baidushoufa"] // } // huaweishoufa{ // manifestPlaceholders = [MTA_CHANNEL_VALUE: "huaweishoufa"] // } // } // 如果嫌上面写法麻烦,也可以这样简写,加上一个批量处理即可. productFlavors { _91 {} wandoujia {} xiaomi {} _360shoufa{} anzhi{} baidushoufa{} huaweishoufa{} } //批量处理 productFlavors.all { flavor -> defchannel = name.startsWith("_") ? name.substring(1) : name flavor.manifestPlaceholders = [MTA_CHANNEL_VALUE: channel] } applicationVariants.all { variant -> variant.outputs.each{ output -> defoutputFile = output.outputFile if(variant.buildType.name.equals('release')) { //可自定义自己想要生成的格式 defchannel = variant.productFlavors[0].name.startsWith("_") ? variant.productFlavors[0].name.substring(1) : variant.productFlavors[0].name deffileName ="v${defaultConfig.versionName}_${releaseTime()}_${channel}.apk" output.outputFile =newFile(outputFile.parent, fileName) } } } applyfrom:'productFlavors.gradle' } defreleaseTime() { returnnewDate().format("yyyyMMdd", TimeZone.getTimeZone("UTC")) } dependencies{ compilefileTree(dir:'libs',include: ['*.jar']) testCompile'junit:junit:4.12' compile'com.android.support:appcompat-v7:23.1.1' compile'com.android.support:design:23.1.1' }

优秀的个人博客,低调大师

Jenkins Linux下SVN的常用语法(学习笔记三)

SVN软件版本管理 1、将文件checkout到本地目录 svn checkout path(path是服务器上的目录) 例如:svn checkout svn://192.168.1.1/pro/domain 简写:svn co 2、往版本库中添加新的文件 svn add file 例如:svn add test.php(添加test.php) svn add *.php(添加当前目录下所有的php文件) 3、将改动的文件提交到版本库 svn commit -m "LogMessage" [-N] [--no-unlock] PATH(如果选择了保持锁,就使用--no-unlock开关) 例如:svn commit -m "add test file for my test" test.php 简写:svn ci 4、加锁/解锁 svn lock -m "LockMessage" [--force] PATH 例如:svn lock -m "lock test file" test.php svn unlock PATH 5、更新到某个版本 svn update -r m path 例如: svn update如果后面没有目录,默认将当前目录以及子目录下的所有文件都更新到最新版本。 svn update -r 200 test.php(将版本库中的文件test.php还原到版本200) svn update test.php(更新,于版本库同步。如果在提交的时候提示过期的话,是因为冲突,需要先update,修改文件,然后清除svn resolved,最后再提交commit) 简写:svn up 6、查看文件或者目录状态 1)svn status path(目录下的文件和子目录的状态,正常状态不显示) 不在svn的控制中;M:内容被修改;C:发生冲突;A:预定加入到版本库;K:被锁定】 2)svn status -v path(显示文件和子目录状态) 第一列保持相同,第二列显示工作版本号,第三和第四列显示最后一次修改的版本号和修改人。 注:svn status、svn diff和 svn revert这三条命令在没有网络的情况下也可以执行的,原因是svn在本地的.svn中保留了本地版本的原始拷贝。 简写:svn st 7、删除文件 svn delete path -m "delete test fle" 例如:svn delete svn://192.168.1.1/pro/domain/test.php -m "delete test file" 或者直接svn delete test.php 然后再svn ci -m 'delete test file‘,推荐使用这种 简写:svn (del, remove, rm) 8、查看日志 svn log path 例如:svn log test.php 显示这个文件的所有修改记录,及其版本号的变化 9、查看文件详细信息 svn info path 例如:svn info test.php 10、比较差异 svn diff path(将修改的文件与基础版本比较) 例如:svn diff test.php svn diff -r m:n path(对版本m和版本n比较差异) 例如:svn diff -r 200:201 test.php 简写:svn di 11、将两个版本之间的差异合并到当前文件 svn merge -r m:n path 例如:svn merge -r 200:205 test.php(将版本200与205之间的差异合并到当前文件,但是一般都会产生冲突,需要处理一下) 12、SVN 帮助 svn help svn help ci ------------------------------------------------------------------------------ 以上是常用命令,下面写几个不经常用的 ------------------------------------------------------------------------------ 13、版本库下的文件和目录列表 svn list path 显示path目录下的所有属于版本库的文件和目录 简写:svn ls 14、创建纳入版本控制下的新目录 svn mkdir: 创建纳入版本控制下的新目录。 用法: 1、mkdir PATH... 2、mkdir URL... 创建版本控制的目录。 1、每一个以工作副本 PATH 指定的目录,都会创建在本地端,并且加入新增 调度,以待下一次的提交。 2、每个以URL指定的目录,都会透过立即提交于仓库中创建。 在这两个情况下,所有的中间目录都必须事先存在。 15、恢复本地修改 svn revert: 恢复原始未改变的工作副本文件 (恢复大部份的本地修改)。revert: 用法: revert PATH... 注意: 本子命令不会存取网络,并且会解除冲突的状况。但是它不会恢复被删除的目录 16、代码库URL变更 svn switch (sw): 更新工作副本至不同的URL。 用法: 1、switch URL [PATH] 2、switch --relocate FROM TO [PATH...] 1、更新你的工作副本,映射到一个新的URL,其行为跟“svn update”很像,也会将服务器上文件与本地文件合并。这是将工作副本对应到同一仓库中某个分支或者标记的方法。 2、改写工作副本的URL元数据,以反映单纯的URL上的改变。当仓库的根URL变动(比如方案名或是主机名称变动),但是工作副本仍旧对映到同一仓库的同一目录时使用这个命令更新工作副本与仓库的对应关系。 17、解决冲突 svn resolved: 移除工作副本的目录或文件的“冲突”状态。 用法: resolved PATH... 注意: 本子命令不会依语法来解决冲突或是移除冲突标记;它只是移除冲突的相关文件,然后让 PATH 可以再次提交。 18、输出指定文件或URL的内容。 svn cat 目标[@版本]...如果指定了版本,将从指定的版本开始查找。 svn cat -r PREV filename > filename (PREV 是上一版本,也可以写具体版本号,这样输出结果是可以提交的)

优秀的个人博客,低调大师

《Effective Java》学习笔记 第二章 创建和销毁对象

第二章 创建和销毁对象 何时以及如何创建对象,何时以及如何避免创建对象,如何确保他们能够适时地销毁,以及如何管理对象销毁之前必须进行的各种清理动作。 1.考虑用静态工厂方法代替构造器 一般在某处获取一个类的实例最常用的方法是提供一个共有的构造器,还有一种方法,就是提供一个共有的静态工厂(static factory method),他只是一个返回类的实例的静态方法。 例: public static Boolean valueOf(boolean b){ return b ? Boolean.TRUE:Boolean.FALSE; } 注意,静态工厂方法与设计模式中的工厂方法模式不同。类可以通过静态工厂方法来提供给它的客户端,而不是通过构造器,提供静态工厂方法而不是公有的构造器,这样做具有几大优势: 优势 静态工厂方法,它们有名称 例如构造器BIgInteger(int,int,Random)返回的BigInteter可能为素数,如果用名为BigInteger.probablePrime的静态工厂方法来表示,显然更为清楚。 不必在每次调用它们的时候都创建一个新的对象 这使得不可变类可以使用预先构建好的实例,或者将构建好的实例缓存起来,进行重复利用,从而避免常见不必要的重复对象,因为程序经常请求创建相同的对象,那么创建对象的代价会很高。Boolean.valueOf(boolean)方法说明了这项技术。静态工厂方法也经常用于实现单例模式。 它们可以返回原返回类型的任何子类型的对象 灵活的静态工厂方法构成了服务提供者框架(Service Provider FrameWork)的基础,例如JDBC。 服务提供者框架:多个服务提供者实现一个服务,系统为服务提供者的客户端提供多个实现,并把他们从多个实现总解耦出来。三个组件:服务接口,这是服务提供者实现的;提供者注册API,这是系统用来注册实现,让客户端访问他们的;服务访问API,是客户端用来获取服务的实例的。 对于JDBC,Connection就是它的服务接口,DriverManager.registerDriver是提供者注册API,DriverManager.getConnection是服务访问API,Driver就是服务提供者接口。 例,下列简单的实现包含了一个服务提供者接口和一个默认提供者: /** * Created by Newtrek on 2017/10/31. * 服务提供者接口 */ public interface Provider { // 提供服务实例,用服务接口返回 Service newService(); } /** * Created by Newtrek on 2017/10/31. * 服务接口 */ public interface Service { // TODO: 2017/10/31 服务特有的方法 写在这儿 } /** * Created by Newtrek on 2017/10/31. */ public class Services { // 构造保护 private Services(){} // provider映射表,保存注册的Provider private static final Map<String ,Provider> providers=new ConcurrentHashMap<>(); // 默认provider的名字 public static final String DEFAULT_PROVIDER_NAME="<def>"; // 注册默认的Provider public static void registerDefaultProvider(Provider p){ registerProvider(DEFAULT_PROVIDER_NAME,p); } // 注册provider public static void registerProvider(String name,Provider p){ providers.put(name,p); } /** * 静态工厂方法返回Service实例 */ public static Service newInstance(){ return newInstance(DEFAULT_PROVIDER_NAME); } public static Service newInstance(String name){ Provider p = providers.get(name); if (p==null){ throw new IllegalArgumentException("No provider registered with name:"+name); } return p.newService(); } } 在创建参数化类型实例的时候,它们是代码变得更加简洁 例:假设HashMap提供了这个静态工厂 public static <K,V> HashMap<K,V> newInstance(){ return new HashMap<K,V>(); } 那么就可以用下面简洁的代码获取实例了。 Map<String,List<String>> m=HashMap.newInstance(); 把这些方法放在自己的工具类中是很实用的。不过现在java7,java8已经实现了HashMap构造的类型参数推测 缺点 类如果不含公有的或者受保护的构造器,就不能被子类化 它们与其他的静态方法实际上没有任何区别 在API文档中,它们没有像构造器那样在API文档中明确标识出来,因为,对于提供了静态工厂方法二不是构造器的类来说,要想查明如何实例化一个类,这是非常困难的。可以通过在类或者接口注释中关注静态工厂,并遵守标准的命名习惯,可以弥补这一劣势。下面是静态工厂方法的一些惯用名称。 valueOf:实际上是类型转换方法。 of:valueOf的一种更为简洁的代替 getInstance:返回的实例是通过方法的参数来描述的,但是不能够说与参数具有同样的值。对于Singleton来说,该方法没有参数,并返回唯一的实例。 newInstance:像getInstance一样,但newInstance能够确保返回的每个实例都与所有其它实例不同。 getType:像getInstance一样,但是在工厂方法处于不同的类中的时候使用。Type表示工厂方法所返回的对象类型。 newType:像newInstance一样,但是在工厂方法处于不同的类中的时候使用,Type表示工厂方法所返回的对象类型。 简而言之,静态工厂方法和公有构造器都各有用处,我们需要理解他们各自的长处。静态工厂通常更加合适,因此切忌第一反应就是提供公有的构造器,而不先考虑静态工厂。 2.遇到多个构造器参数时要考虑用构建器 这个就是Builder设计模式 3.用私有构造器或者枚举类型强化Singleton属性 这个是单例模式的注意事项,选择最好的单例模式实现 4.通过私有构造器强化不可实例化的能力 有时候需要编写一些只包含静态方法和静态域的类,这些类的名声很不好,因为有些人在面向对象的语言中滥用这样的类来编写过程化的程序,尽管如此,他们也确实有它们的好处,比如常见的工具类java.lang.Math等,都是这样。方正这样不可以实例化的类,最好把他的构造器设置为私有。 例如: public class UtilityClass{ private UtilityClass(){ throw new AssertionError(); } } 5.避免创建不必要的对象 一般来说,最好能重用对象而不是再每次需要的时候就创建一个相同功能的新对象,如果对象是不可变的,他就始终可以被重用。 简单的例子:字符串 String s = new String("stringtest");//不要这样做,因为该语句每次执行的时候都会创建一个新的String实例,没必要 // 改进后的版本,这个版本只用了一个String实例,而不是每次执行的时候都创建一个新的实例。对于再同一台虚拟机中运行的代码,只要它们包含相同的字符串自字面常量,该对象就可以被重用。 String s = "stringtest"; 对于同时提供了静态方法和构造器方法的不可变类,通常可以使用静态工厂方法而不是构造器,以避免创建不必要的对象。 优先使用基本类型,而不是装箱基本类型,当心无意识的自动装箱。 也不要错误地认为本条目暗示着“创建对象的代价非常昂贵,我们应该尽可能地避免创建对象”,相反,由于小对象地构造器制作很少量地显示工作,所以,小对象地创建和回收动作是非常廉价地。 通过维护自己的对象池来避免创建对象比不是一种好的做法,除非池中的对象是非常重量级的,一般数据库连接池常用。 6 消除过期的对象引用 不要以为Java有垃圾回收机制,能自动管理内存,自动回收垃圾,就可以不管了,其实不然。 内存泄漏的例子 public class Stack { private Object[] elements; private int size = 0; private static final int DEFAULT_CAPACITY = 16; public Stack(){ elements = new Object[DEFAULT_CAPACITY]; } public void push(Object object){ ensureCapacity(); elements[size++] = object; } public Object pup(){ if (size == 0){ throw new EmptyStackException(); } return elements[size--]; } private void ensureCapacity(){ if (elements.length == size){ elements = Arrays.copyOf(elements,size*2+1); } } } 这段程序并没有明显的错误,如果是栈先是增长,然后再收缩,那么,从栈中弹出来的对象将不会被当作垃圾回收,因为里面的数组里引用着它,栈内部维护着这些对象的过期引用,过期引用就是指永远也不会再被解除的引用。 这类问题的修复方法很简单:一旦对象引用已经过期,只需清空这些应用即可。 没必要对于每一个对象引用,一旦程序不再用到它,就把它清空。清空对象引用应该是一种例外,而不是一种规范行为,消除过期引用最好的办法是让包含该对象的变量结束其生命周期。一般而言,只要类是自己管理内存,程序员就应该警惕内存泄漏问题,一旦元素被释放掉,则该元素中包含的任何对象引用都应该被清空。 内存泄漏的另一个常见来源是缓存,一旦你把对象放在缓存中,他就很容易被遗忘掉,从而使得它不再有用之后很长一段时间内仍然留在缓存中。可以用WeakHashMap 内存泄漏的第三个常见来源是监听器和其他回掉,一般都要取消注册,或者用弱引用 内存泄漏通常不会表现成明显的失败,所以他们可以再一个系统中存在很多年,往往通过仔细检查代码,借助于Heap刨析工具才能发现内存泄漏问题。 7 避免使用终结方法 终结方法(finalizer)通常是不可预测的,也是很危险的,一般情况下是不必要的。 C++的析构器是回收一个对象所占用资源的常规方法,是构造器所必须的对应物,也可以用来回收其他的非内存资源,而在Java中,一般用try-finally块来完成类似的工作

优秀的个人博客,低调大师

JVM学习系列:了解JVM options参数配置 & 看懂GC日志

摘要 java有内置的垃圾回收器做内存回收,通过强引用、软引用、弱引用和虚引用给对象做"标记",告诉垃圾回收器在什么时机回收什么内存。我先通过JVM options参数探测JVM内部不同垃圾回收的策略。 JVM初始参数 minimum size of heap:10MB maximum size of heap:20MB new size of heap:5MB -Xms10m -Xmx20m -Xmn5m -XX:ReservedCodeCacheSize=240m -XX:+UseCompressedOops -XX:+PrintGCDateStamps -XX:+PrintGCDetails -Xloggc:./gclogs JVM初始内存分配: 截图是以空main方法运行后JVM的内存使用概要。新生代内存大小为5MB,PSYoungGen区可用内存大小为4608K,eden、from和to区分别为4MB、512K和512K;老年代可用内存大小为5120K。 所需分配的内存小于新生代大小 // ONE_MB_SIZE = 1024 * 1024 byte[] allocate1 = new byte[ONE_MB_SIZE]; 创建allocate1数组在eden区分配了4096KB*0.25=1MB内存。 所需分配的内存大于新生代大小: byte[] allocate1 = new byte[3 * ONE_MB_SIZE]; JVM将3MB的对象放到了老年代:为什么JVM不GC然后在新生代上分配3MB空间?这和内存分配与回收策略有关: * 对象优先在eden区分配 * 大对象直接进入老年代 * 长时间还活着的对象进入老年代 即: 新生代初始36%的内存空间没有可GC的空间。 新生代的eden+from剩余3.1MB,足以提供3MB空间,但内存按page分配(4K/page),如果在新生代分配会使得对象分开保存在不同的区(eden和from),是否存储对象的内存只能在一个区里,这点待验证。 垃圾收集器为保吞吐量,当新生代无足够内存时,把对象分配到了老年代。 GC/Full GC 初始我们给heap分配了最大20MB的内存空间,下面看下GC的场景。此时发生了GC和Full GC:刨除初始被占用的36%的eden区,20MB的heap大小不满足内存分配要求,触发了java.lang.OutOfMemoryError: Java heap space错误。 此时将allocate1=null,触发GC,heap刚好可以完成内存分配。此时是在释放了eden空间后,转移到老年代进行内存分配: 看懂GC日志 To be continued...

优秀的个人博客,低调大师

Ansible-playbook loops循环with_items(学习笔记二十一)

文件 [root@ansible-server ansible]# tree ./ ./ ├── hosts └──loops.yaml hosts 文件 [web] 192.168.10.11 192.168.10.12 loops.yaml文件 --- - hosts: all gather_facts: False tasks: - name: debug loops debug: msg="yum install -y {{ item }}" yum: name={{ item }} with_items: - pcre - pcre-devel - nginxPS:{{ item }} 定义变量 with_items 是 python list 数据结构,task会循环读取list里面的值。key的名称是item。 - pcre - pcre-devel - nginx 如果其它软件包,可将软件包名称依次写在下面。 批量安装 #ansible-playbook -i hosts loops.yaml PLAY [all] ******************************************************************** TASK: [debug loops] *********************************************************** ok: [192.168.10.11] => (item=pcre,pcre-devel,nginx) ok: [192.168.10.12] => (item=pcre,pcre-devel,nginx) PLAY RECAP ******************************************************************** 192.168.10.11: ok=1 changed=0 unreachable=0 failed=0 192.168.10.12 : ok=1 changed=0 unreachable=0 failed=0

优秀的个人博客,低调大师

Python机器学习算法入门之梯度下降法实现线性回归

1. 背景 文章的背景取自An Introduction to Gradient Descent and Linear Regression,本文想在该文章的基础上,完整地描述线性回归算法。部分数据和图片取自该文章。没有太多时间抠细节,所以难免有什么缺漏错误之处,望指正。 线性回归的目标很简单,就是用一条线,来拟合这些点,并且使得点集与拟合函数间的误差最小。如果这个函数曲线是一条直线,那就被称为线性回归,如果曲线是一条二次曲线,就被称为二次回归。数据来自于GradientDescentExample中的data.csv文件,共100个数据点,如下图所示: 我们的目标是用一条直线来拟合这些点。既然是二维,那么y=b+mx这个公式相信对于中国学生都很熟悉。其中b是直线在y轴的截距(y-intercept),m是直线的斜率(slope)

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Rocky Linux

Rocky Linux

Rocky Linux(中文名:洛基)是由Gregory Kurtzer于2020年12月发起的企业级Linux发行版,作为CentOS稳定版停止维护后与RHEL(Red Hat Enterprise Linux)完全兼容的开源替代方案,由社区拥有并管理,支持x86_64、aarch64等架构。其通过重新编译RHEL源代码提供长期稳定性,采用模块化包装和SELinux安全架构,默认包含GNOME桌面环境及XFS文件系统,支持十年生命周期更新。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

用户登录
用户注册