最近不少同学都在找工作,给大家分享一波我这边面试某知名自研公司一二面面试复盘记录,两轮面试均已通过。
主要考察质量保障,手撕代码,编程基础,性能测试,JVM等等。
需要详细视频答案分析的可以通过文末二维码识别加入我创建的软件测试面试题库知识星球获取!欢迎围观!
一面:
1、自我介绍
2、业务架构介绍
3、主要做的测试工作
4、最近做的比较有挑战性的一个产品测试工作
5、如何保证试算的金额是正确的
6、如何保证线上保险产品的配置问题不会出现
7、保险产品增加修改配置时,其web是动态变化的。你们是如何保证前端的质量
8、整个业务链路的测试风险
9、如何保证上线前 上线中(生产环境部署但不对外开放) 上线后的质量
10、介绍一下自动化体系-模块、工作量、参数人、技术选型等
11、主要负责的自动化模块并介绍一下可以优化的点
12、接口自动化测试的比重和覆盖率
13、如何开展的性能测试
14、针对某一个接口诊断性能瓶颈
15、sql没问,直接做的笔试
16、java中如果需要频繁对字符串操作,最好选择的数据类型和原因。并介绍一下String、StringBuffer、StringBuilder的区别----这里我深入到源码和分配过程,所以没问其他的java问题
在Java中,如果需要频繁进行字符串操作,选择的数据类型通常取决于操作的类型和需求。以下是一些常见的数据类型选择及其原因:
-
String:当字符串内容不变时,或者字符串操作主要是读取和拼接时,使用
String
是合适的。String
是不可变的,这意味着一旦创建,它的值就不能被改变。每次对String
对象进行修改,如拼接或替换,都会生成一个新的String
对象。 -
StringBuffer:在多线程环境下,如果需要频繁地修改字符串内容,
StringBuffer
是一个好的选择。StringBuffer
是线程安全的,它的所有方法都是同步的,这意味着在多线程环境中,StringBuffer
可以保证数据的一致性。 -
StringBuilder:如果不需要考虑线程安全,且需要频繁修改字符串内容,
StringBuilder
是更优的选择。StringBuilder
在性能上优于StringBuffer
,因为它不是线程安全的,所以没有同步开销。从Java 5开始,StringBuilder
被引入,作为非线程安全的字符串缓冲区,用于单线程环境。
String、StringBuffer、StringBuilder的区别:
String:
-
不可变:一旦创建,字符串内容就不能被改变。
-
每次修改都会生成一个新的
String
对象。 -
适合于字符串常量或不需要频繁修改的场景。
StringBuffer:
-
可变:可以修改字符串内容。
-
线程安全:所有方法都是同步的,可以在多线程环境中使用。
-
由于同步的开销,性能相对较低。
StringBuilder:
-
可变:可以修改字符串内容。
-
非线程安全:没有同步机制,因此在单线程中性能更好。
-
适合于单线程环境,需要频繁修改字符串的场景。
在实际应用中,选择哪种类型通常取决于具体的使用场景。如果操作涉及到多线程,并且需要保证数据的一致性,那么StringBuffer
是首选。如果是单线程环境,并且需要频繁地修改字符串,那么StringBuilder
是更好的选择。如果字符串内容不需要修改,只是需要拼接或读取,那么使用String
就足够了。
17、反问----主要问了入职的成长发展和工作概况;还有面试的整体流程
18、编程题:①有两个相同结构的表A、B,都有tcontext、tid字段。问题:修改A的tcontext内容为B的tcontext内容。修改方式:B表通过tid去匹配A表的tid。如能匹配就修改
UPDATE tableA SET tcontext = tableB.tcontext WHERE tid = tableB.tid
②给你一串数字 把最后2位作为放到前面后输出
使用切片
# 假设我们有一个数字列表
numbers = [12, 34, 56, 78, 90]
# 找到最后两位数字
last_two_digits = numbers[-2]
# 将最后两位数字放到前面
new_numbers = [last_two_digits] + numbers[:-2]
print(new_numbers)
③给你一个全是单字母的字符串列表 然后按字母出现的次数从大到小打印出来。如{a,a,c,b,b,b,d,d,d}则输出b,b,b,d,d,d,a,a,c
# 定义一个函数来统计每个字符出现的次数
def count_characters(char_list):
count_dict = {}
for char in char_list:
if char in count_dict:
count_dict[char] += 1
else:
count_dict[char] = 1
return count_dict
# 定义一个函数来根据字符出现次数排序并打印
def sort_and_print(char_list):
# 首先统计每个字符出现的次数
count_dict = count_characters(char_list)
# 将字符和它们的计数转换为一个列表,然后根据计数进行排序
sorted_chars = sorted(count_dict.items(), key=lambda x: x[1], reverse=True)
# 打印排序后的字符列表
for char, count in sorted_chars:
print(char * count, end=' ') # 打印字符及其重复次数
# 示例字符串列表
char_list = ['a', 'a', 'c', 'b', 'b', 'b', 'd', 'd', 'd']
# 调用函数
sort_and_print(char_list)
二面:
1、自我介绍
2、介绍一下业务链路
3、保险规则和计算金额如何保证
4、有没有碰到影响面比较大的bug
5、介绍一下最近比较复杂的项目对应的金额与规则质量保证
6、项目中主要涉及的风险及风险应对措施
7、你觉得线上环境客户也许会碰到哪些问题以及你们如何处理
8、质量保证思路考察:购物、下单、支付。如何保证这个链路的质量以及相关测试用例设计
9、介绍一下自动化框架以及相应成果
10、你负责的自动化哪部分内容,怎么实现的。还有没有优化的地方
11、性能测试中full gc为什么会带来比较大的性能损耗
在性能测试中,Full GC(Full Garbage Collection)即全量垃圾回收,是指Java虚拟机(JVM)中对整个堆内存(包括新生代和老年代)进行的垃圾回收操作。
-
回收时间长:Full GC需要清理整个堆内存,这通常比新生代垃圾回收(Minor GC)要耗时得多。在Full GC发生期间,所有的应用线程都会被暂停,导致服务响应时间变长。
-
频繁发生:如果系统设计或配置不当,Full GC可能会频繁发生。频繁的Full GC会导致系统性能出现锯齿形波动,严重影响系统的稳定性和响应速度
-
CPU资源占用高:Full GC过程中,JVM需要进行大量的内存清理工作,这会占用大量的CPU资源。在某些情况下,Full GC甚至会导致CPU使用率飙升至100%,进一步加剧性能问题
12、介绍一下full gc的触发条件
Full GC(全量垃圾回收)的触发条件通常与Java虚拟机(JVM)的内存管理和垃圾回收机制有关。以下是一些常见的Full GC触发条件:
-
老年代空间不足:当老年代(Old Generation)的内存空间被对象填满,且新生代(Young Generation)的垃圾回收(Minor GC)无法释放足够的内存时,JVM会触发Full GC来清理整个堆内存。
-
永久代(PermGen)空间不足:在Java 8之前,JVM有一个称为永久代(Permanent Generation)的内存区域,用于存储类的元数据。如果PermGen空间不足,也会触发Full GC。
-
内存泄漏:内存泄漏会导致不再使用的对象无法被垃圾回收器回收,随着时间的推移,这些对象会逐渐消耗掉老年代的内存,最终触发Full GC。
13、触发full gc时你如何去排查
通过工具去做内存dump进行分析是否有内存泄漏现象
- 监控和日志分析:
-
检查JVM监控工具(如JConsole、VisualVM、GCViewer等)的输出,分析Full GC的频率、持续时间和影响。
-
查看GC日志,了解Full GC发生的时间、持续时间以及回收前后的内存使用情况。
- 堆内存分析:
-
使用堆转储文件(Heap Dump)分析工具(如MAT、JProfiler等)来分析Full GC前后的堆内存使用情况。
-
识别内存中的对象,特别是大对象和内存泄漏的潜在来源。3. 代码审查:
-
审查代码,特别是那些可能创建大对象或长时间存活对象的部分。
-
检查是否有不必要的对象保留,导致内存泄漏。
- JVM参数调整:
-
根据监控和分析结果,调整JVM参数,如堆大小(-Xms, -Xmx)、新生代大小(-Xmn)、Eden区大小等。
-
调整垃圾收集器的配置,如CMS的启动阈值(-XX:CMSInitiatingOccupancyFraction)。
14、简单介绍一下jvm中堆空间 垃圾回收机制
堆空间结构:
-
新生代(Young Generation):
-
被划分为三个部分:Eden区和两个Survivor区(S0和S1)。
-
大部分新创建的对象首先分配在Eden区。
-
当Eden区满时,会触发Minor GC,存活的对象会被复制到一个Survivor区。
-
经过多次Minor GC后,对象在Survivor区之间来回复制,如果对象存活时间足够长,则会被提升到老年代。
-
-
老年代(Old Generation):
-
存储长时间存活的对象。
-
当老年代空间不足时,会触发Full GC,这是一个成本较高的操作,因为它需要扫描整个堆空间。
- 元空间(Metaspace):
-
替代了Java 7及以前版本中的永久代(PermGen)。
-
用于存储类的元数据,如类的静态结构,如类定义、常量池等。
-
元空间不在虚拟机内存中,而是使用本地内存。
垃圾回收机制:
- Young GC:
-
发生在新生代,当Eden区满时触发。
-
存活的对象被复制到Survivor区,这个过程称为复制(Copying)算法。
-
Minor GC相对快速,因为新生代的对象大多数都是朝生夕死。
- Full GC:
-
发生在整个堆空间,包括新生代和老年代。
-
通常由老年代空间不足触发,也可能由系统请求(如
System.gc()
)或JVM参数配置触发。 -
Full GC会停止所有的应用线程,因此可能引起应用程序的延迟。
- 垃圾回收算法:
-
标记-清除(Mark-Sweep):首先标记所有需要回收的对象,然后清除这些对象。
-
复制(Copying):新生代中使用的算法,将存活的对象复制到另一块干净的内存区域。
-
标记-清除-整理(Mark-Sweep-Compact):在标记清除后,对内存进行整理,消除内存碎片。
-分代收集(Generational Collection):基于对象生命周期的假设,将对象分为新生代和老年代。
- 垃圾收集器:
- JVM提供了多种垃圾收集器,如Serial、Parallel、CMS、G1、ZGC等,每种收集器适用于不同的应用场景和性能需求。
15、现在手里的offer
16、反问
感谢每一个认真阅读我文章的人,礼尚往来总是要有的,虽然不是什么很值钱的东西,如果你用得到的话可以直接拿走:
这些资料,对于【软件测试】的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴上万个测试工程师们走过最艰难的路程,希望也能帮助到你!有需要的小伙伴可以点击下方小卡片领取